2016-06-28 3 views
1

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

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

Из того, что я знаю, запрос возвращает 1500 строк и делает SUM и COUNT из других таблиц.

SELECT 
p.id, 
p.datecreate, 
p.title, 
p.address, 
p.address2, 
p.code_postal, 
p.ville, 
p.description, 
p.description_admin, 
p.idstatut, 
p.idstatut_admin, 
p.reference, 
p.star, 
p.logo, 
p.deleted, 
cc.value as starcolor, 
p.idsociete, 
soc.nom as societe_nom, 
s.titlestatut, 
s.fontcolor, 
s.label as label, 
sa.titlestatut as titlestatut_admin, 
sa.fontcolor as fontcolor_admin, 
sa.label as label_admin, 
(SELECT SUM(nbr) FROM plans as cplans WHERE cplans.idprojets = p.id) as count_commandes, 
(SELECT count(id) FROM files as cfiles WHERE cfiles.idprojets = p.id AND cfiles.folder = '1' AND cfiles.bat_valid = '0') as count_averifier, 
(SELECT count(rowid) FROM files_modif_title as cfmt WHERE cfmt.idprojets = p.id AND cfmt.statut = '7' AND cfmt.hide = '0') as count_modif_nohide, 
(SELECT count(rowid) FROM files_modif_title as cfmt WHERE cfmt.idprojets = p.id AND cfmt.statut = '7' AND cfmt.hide IN (1)) as count_modif_hide, 
(SELECT count(id) FROM files as cfiles WHERE cfiles.idprojets = p.id AND cfiles.folder = '2' AND cfiles.bat_valid = '0') as count_bat_attente, 
(SELECT count(id) FROM files as cfiles WHERE cfiles.idprojets = p.id AND cfiles.folder = '2' AND cfiles.bat_valid = '1') as count_bat_valider 
FROM projets as p INNER JOIN societe AS soc ON p.idsociete = soc.id 
INNER JOIN statuts AS s ON p.idstatut = s.id 
INNER JOIN statuts AS sa ON p.idstatut_admin = sa.id 
LEFT JOIN const AS cc ON cc.name = p.star AND cc.parent = 'star' 
WHERE p.idstatut IN (3) 
AND p.deleted = 0 
GROUP BY p.id 
ORDER BY p.datecreate DESC 

Спасибо, ребята!

Редактировать -----

Вот что я сделал, это может быть лучше?

SELECT 
    p.id, 
    p.datecreate, 
    p.title, 
    p.address, 
    p.address2, 
    p.code_postal, 
    p.ville, 
    p.description, 
    p.description_admin, 
    p.idstatut, 
    p.idstatut_admin, 
    p.reference, 
    p.star, 
    p.logo, 
    p.deleted, 
    cc.value as starcolor, 
    p.idsociete, 
    soc.nom as societe_nom, 
    s.titlestatut, 
    s.fontcolor, 
    s.label as label, 
    sa.titlestatut as titlestatut_admin, 
    sa.fontcolor as fontcolor_admin, 
    sa.label as label_admin, 
    CC.count_commandes, 
    CA.count_averifier, 
    CMN.count_modif_nohide, 
    CMH.count_modif_hide, 
    CBA.count_bat_attente, 
    CBV.count_bat_valider 
FROM 
    projets as p 
     INNER JOIN societe AS soc 
      ON p.idsociete = soc.id 
     INNER JOIN statuts AS s 
      ON p.idstatut = s.id 
     INNER JOIN statuts AS sa 
      ON p.idstatut_admin = sa.id 
     LEFT JOIN const AS cc 
      ON cc.name = p.star 
      AND cc.parent = 'star' 
     LEFT JOIN (

       SELECT idprojets, SUM(nbr) as count_commandes 
       FROM plans 
       GROUP BY idprojets 
      ) AS CC 
      ON p.id = CC.idprojets 
     LEFT JOIN (

       SELECT idprojets, COUNT(*) AS count_averifier 
       FROM files 
       GROUP BY idprojets 
       WHERE cfiles.folder = 1 AND cfiles.bat_valid = 0 
      ) AS CA 
      ON p.id = CA.idprojets 
     LEFT JOIN (

       SELECT idprojets, COUNT(*) as count_modif_nohide 
       FROM files_modif_title 
       WHERE statut = 7 AND hide = 0 
       GROUP BY idprojets 
      ) AS CMN 
      ON p.id = CMN.idprojets 
     LEFT JOIN (

       SELECT idprojets, COUNT(*) as count_modif_hide 
       FROM files_modif_title 
       WHERE statut = 7 AND hide = 1 
       GROUP BY idprojets 
      ) AS CMH 
      ON p.id = CMH.idprojets 
     LEFT JOIN (

       SELECT idprojets, COUNT(*) 
       FROM files 
       WHERE folder = 2 AND bat_valid = 0 
       GROUP BY idprojets 
      ) AS CBA 
      ON p.id = CBA.idprojets 
     LEFT JOIN (

       SELECT idprojets, COUNT(*) 
       FROM files 
       WHERE folder = 2 AND bat_valid = 1 
       GROUP BY idprojets 
      ) AS CBV 
      ON p.id = CBV.idprojets 
WHERE 
    p.idstatut IN (3) 
    AND p.deleted = 0 
GROUP BY p.id 
ORDER BY p.datecreate DESC; 

Благодаря тому, что вы сказали, основная проблема заключалась в том, что 6 SELECT встроены в предложение SELECT. Они оцениваются для каждой записи, созданной приложением, поэтому она выполняет 1500 x 6 = 9000 запросов! Сделав это, у меня было 9001 запросов и теперь только 7, поскольку подзапросы оцениваются только один раз во время выполнения. Это верно ?

+1

В общем правиле GROUP BY указано: Если указано предложение GROUP BY, каждая ссылка столбца в списке SELECT должна либо идентифицировать столбец группировки, либо быть аргументом функции набора. – jarlh

+1

Это выглядит отлично. Вы хотите, чтобы у вас были правильные индексы. –

ответ

2

Это часть вы демонстративно хотите улучшить:

(SELECT SUM(nbr) FROM plans as cplans WHERE cplans.idprojets = p.id) as count_commandes, 
(SELECT count(id) FROM files as cfiles WHERE cfiles.idprojets = p.id AND cfiles.folder = '1' AND cfiles.bat_valid = '0') as count_averifier, 
(SELECT count(rowid) FROM files_modif_title as cfmt WHERE cfmt.idprojets = p.id AND cfmt.statut = '7' AND cfmt.hide = '0') as count_modif_nohide, 
(SELECT count(rowid) FROM files_modif_title as cfmt WHERE cfmt.idprojets = p.id AND cfmt.statut = '7' AND cfmt.hide IN (1)) as count_modif_hide, 
(SELECT count(id) FROM files as cfiles WHERE cfiles.idprojets = p.id AND cfiles.folder = '2' AND cfiles.bat_valid = '0') as count_bat_attente, 
(SELECT count(id) FROM files as cfiles WHERE cfiles.idprojets = p.id AND cfiles.folder = '2' AND cfiles.bat_valid = '1') as count_bat_valider 

Вы можете использовать условная агрегация для этого и объединение таблиц только один раз:

count(nbr) as.., 
count(CASE WHEN cfiles.folder = '1' and cfiles.bat_valid = '0' then id END) as .., 
count(CASE WHEN cfiles.folder = '2' and cfiles.bat_valid = '0' then id END) as .., 
count(CASE WHEN cfiles.folder = '2' and cfiles.bat_valid = '1' then id END) as .., 
........ 

Добавить стыки

JOIN files cfiles 
ON(cfiles.idprojets = p.id) 

сделать то же самое для files_modif_title

+0

Спасибо, это хороший способ улучшить его! Я зарабатываю 80% времени во время выполнения: D – Majestic

1
  1. Надеется, ваша главная таблица имеет Индексацию
  2. Вместо использования подзапроса, используйте присоединиться
+0

Спасибо, это помогло мне создать новую версию! – Majestic

1

попытки,

SELECT 
p.id, 
p.datecreate, 
p.title, 
p.address, 
p.address2, 
p.code_postal, 
p.ville, 
p.description, 
p.description_admin, 
p.idstatut, 
p.idstatut_admin, 
p.reference, 
p.star, 
p.logo, 
p.deleted, 
cc.value as starcolor, 
p.idsociete, 
soc.nom as societe_nom, 
s.titlestatut, 
s.fontcolor, 
s.label as label, 
sa.titlestatut as titlestatut_admin, 
sa.fontcolor as fontcolor_admin, 
sa.label as label_admin, 
count (case when cfiles.folder = '2' AND cfiles.bat_valid = '0' then 1 end) count_bat_attente, 
count (case when cfiles.folder = '1' AND cfiles.bat_valid = '0' then 1 end) count_averifier, 
count (case when cfiles.folder = '2' AND cfiles.bat_valid = '1' then 1 end) count_bat_valider, 
SUM(nbr) as count_commandes, 
count (case when cfmt.statut = '7' AND cfmt.hide = '0' then 1 end) count_modif_nohide, 
count (case when cfmt.statut = '7' AND cfmt.hide IN (1) then 1 end) count_modif_hide 

FROM projets as p INNER JOIN societe AS soc ON p.idsociete = soc.id 
INNER JOIN statuts AS s ON p.idstatut = s.id 
INNER JOIN statuts AS sa ON p.idstatut_admin = sa.id 
left join files on files.idprojets=p.id 
left join plans cplans on cplans.idprojets = p.id 
left join files_modif_title cfmt on cfmt.idprojets = p.id 
LEFT JOIN const AS cc ON cc.name = p.star AND cc.parent = 'star' 
WHERE p.idstatut IN (3) 
AND p.deleted = 0 
GROUP BY p.id 
ORDER BY p.datecreate DESC 
1

Чтобы ответить на ваш вопрос "Вот что я сделал, это может быть лучше?", ..

Принимая во внимание, что ваша логика 9001 действительна, есть еще одна проблема ... LEFT JOIN (SELECT ...) строит временную таблицу некоторого n umber (1500?) строк. Если вы используете версию до 5.6, то эти таблицы tmp не имеют индекса и должны быть повторно проверены. Теперь мы говорим о 1500 * 1500 * 6 = миллионах операций, а не просто 9001.

Даже с 5.6 есть дополнительный шаг (6 раз), чтобы обнаружить оптимальный индекс и построить его.

Но, ваш реальный вопрос: «Как я могу ускорить это?». Другие хорошо ответили на это.

Смежные вопросы