2016-01-02 2 views
2

Я хотел бы улучшить производительность этого запроса, который теперь занимает 13 секунд, чтобы вернуть результат.Улучшение производительности запросов этого SQL

Главный стол имеет более 2 000 000 записей. Результат содержит всего 34 записи. Таблицы имеют индексы на r.date_gps.

SELECT 
    r.id, 
    c.name, 
    CONCAT(v.title, '', v.plaque) AS title,v.type_vehicle, 
    r.sn, 
    r.lat, 
    r.lng, 
    r.direction, 
    r.date_db, 
    r.date_gps, 
    r.volt_main, 
    r.speed, 
    r.ing, 
    t.sat_fix, 
    r.sat 
FROM registers r 
JOIN trackers t ON t.cod = r.sn 
JOIN installations i ON t.id = i.trackers_id 
JOIN vehicles v ON v.id = i.vehicles_id 
JOIN clients c ON c.id = v.clients_id 
WHERE r.date_gps = (
    SELECT MAX(rr.date_gps) FROM registers rr WHERE r.sn = rr.sn 
) 
AND c.management_id = p_management 
GROUP BY r.sn 
ORDER BY r.date_gps DESC; 
+1

Вы проверили план объяснения? – Incognito

+0

Пожалуйста, добавьте в план выполнения запроса вопрос. – eis

ответ

2

К сожалению Mysql не поддерживает Row_Number оконные функции

Try переписывание sub-query к INNER JOIN

SELECT r.id, 
     c.NAME, 
     Concat(v.title, '', v.plaque) AS title, 
     v.type_vehicle, 
     r, 
     sn, 
     ..... 
FROM registers r 
     JOIN trackers t 
     ON t.cod = r.sn 
     JOIN installations i 
     ON t.id = i.trackers_id 
     JOIN vehicles v 
     ON v.id = i.vehicles_id 
     JOIN clients c 
     ON c.id = v.clients_id 
      AND c.management_id = p_management 
     INNER JOIN (SELECT Max(rr.date_gps) AS date_gps, 
          sn 
        FROM registers rr 
        GROUP BY sn) a 
       ON r.sn = a.sn 
        AND r.date_gps = a.date_gps 
GROUP BY r.sn 
ORDER BY r.date_gps DESC; 
+0

Непонятно, насколько агрегирование всей таблицы «регистров» вместо поиска только совпадающих строк улучшит производительность. Будет интересно услышать от OP. –

0

При взгляде на улучшении производительности запросов, место, чтобы начать это FROM и WHERE Положения:

FROM registers r JOIN 
    trackers t 
    ON t.cod = r.sn JOIN 
    installations i 
    ON t.id = i.trackers_id JOIN 
    vehicles v 
    ON v.id = i.vehicles_id JOIN 
    clients c 
    ON c.id = v.clients_id 
WHERE r.date_gps = (SELECT MAX(rr.date_gps) FROM registers rr WHERE r.sn = rr.sn 
        ) AND 
     c.management_id = p_management 
GROUP BY r.sn 
ORDER BY r.date_gps DESC; 

Предлагаемые номера: clients(management_id, id), vehicles(clients_id, id), installations(vehicles_id, trackers_id), trackers(trackers_id, cod) и registers(sn, date_gps).

Это будет (по существу) поощрять оптимизатор к внедрению соединений, начиная с таблицы clients, фильтруя по management_id. Затем соединения будут использовать только индексы, и эта часть запроса должна быть довольно быстрой. Конечно, если у вас есть тысячи или миллионы совпадений, то GROUP BY все равно замедлит запрос (и MySQL имеет несколько вариантов улучшения производительности GROUP BY).

0

Чтобы ускорить запрос с такой связкой данных, сначала необходимо сжать свой основной стол. Иногда два запроса лучше, чем один.

Постарайтесь, чтобы получить, где данные первого

SELECT MAX(rr.date_gps) FROM registers rr WHERE r.sn = rr.sn 

И затем использовать результат, так что добавьте его в основной запрос.

Здесь также можно использовать подзапрос, прежде чем присоединяться к другим таблицам.

, например

SELECT registers.* 
FROM (
    SELECT registers.id 
    FROM registers 
    WHERE <My WHERE Conditions> 
) AS registers_sub 

INNER JOIN registers 
ON registers_sub.id = registers.id 

, а затем сделать остальную часть вашего запроса. Таким образом, у вас есть небольшой набор данных, когда вы делаете много объединений и групп.

И последний намек, не использовать * в SELECT, сегмент, если вам не нужно все, D

Greetings

0

Спасибо всем за вашу помощь в попытке повышения производительности запросов.

VR46, переписал запрос в этом формате, но основной банк продолжил медленно.

ZFNerd, также разделенный на два запроса, имеет ту же медлительность. Gordon Linoff, поля уже проиндексированы.

У меня есть запрос с использованием другого поля, чтобы получить максимальную актуальность, но это было не то, что я хотел, потому что какое-то оборудование сначала отправляет текущие данные после старейших и, таким образом, не может найти самую последнюю запись. Но некоторые могут быть настроены для отправки первой самой ранней. Я думаю, что сейчас я буду использовать этот формат для обновления быстро и проблемы будут минимальными.

SELECT c.name,CONCAT(v.title,' ',v.plaque) AS title,v.type_vehicle,r.id, 
r.sn,r.lat,r.lng, r.direction,r.date_db,r.date_gps,r.volt_main,r.speed, 
r.ign,r.sat_fix,r.sat 
FROM registers r 
JOIN trackers t ON t.cod = r.sn 
JOIN installations i ON t.id = i.trackers_id 
JOIN vehicles v ON v.id = i.vehicles_id 
JOIN clients c ON c.id = v.clients_id 
JOIN (
    SELECT rr.sn, MAX(rr.id) AS id FROM registers rr GROUP BY sn 
) AS L2 ON r.sn = L2.sn AND r.id = L2.id 
AND c.management_id = p_management 
GROUP BY r.sn; 
0

Хотя другие запросы могут помочь с помощью группы select max(), вам может быть лучше пойти по другому маршруту. Похоже, вы отслеживаете транспортные средства, перемещающие товары какого-либо типа и требующие последнего места в любой точке.

Возможно, вам будет лучше обновить таблицу «Трекеры» и добавить столбец для LastGPSDate. Затем с помощью триггера при вставке в таблицу Date_GPS выпустите обновление для соответствующего Trackers.LastGPSDate, где COD = gps.sn, из которого вы вставляете (на основе вашего условия соединения). Тогда ваш запрос будет упрощен до

SELECT 
     r.id, 
     c.name, 
     CONCAT(v.title, '', v.plaque) AS title,v.type_vehicle, 
     r.sn, 
     r.lat, 
     r.lng, 
     r.direction, 
     r.date_db, 
     r.date_gps, 
     r.volt_main, 
     r.speed, 
     r.ing, 
     t.sat_fix, 
     r.sat 
    FROM 
     clients c 
     JOIN vehicles v 
      ON c.id = v.clients_id 
      JOIN installations i 
       ON v.id = i.vehicles_id 
       join trackers t 
       ON i.trackers_id = t.id 
       JOIN registers r 
        ON t.cod = r.sn 
        AND t.LastGPSDate = r.date_gps 
    WHERE 
     c.management_id = p_management 
    ORDER BY 
     t.LastGPSDate DESC; 

я отменил заказ таблиц, чтобы лучше соответствовать тому, что вы ищете. Начните с одного клиента с конкретным, где с помощью идентификатора управления. Затем, только их транспортные средства к установкам, трекеры и, наконец, регистрируются.

Я бы тогда предложить следующие показатели индексов таблицы клиентов (management_id, ID) транспортных средств (ID, clients_id) установки (trackers_id, vehicles_id) трекеры (LastGPSDate, треска, идентификатор, sat_fix) регистры (SN , date_gps)

Из-за условия соединения, конкретно ограничивающего один идентификатор управления, я поместил его в первую позицию индекса.

Таким образом, из двух или более миллионов записей, BULK ваших данных может состоять из 20, 30, 100 различных идентификаторов управления, зачем генерировать MAX, применяемый к всем регистрам каждый раз при его запуске. Штампом даты/времени каждый раз с помощью триггера вы получаете свои данные быстрее и только для тех клиентов, которых вы хотите в этот момент.