MySQL group by убивает производительность запросов

У меня есть запрос MySQL, который в настоящее время выбирает и объединяет 13 таблиц и, наконец, группирует ~60 тыс. Строк. Запрос без группировки занимает ~0 мс, но с группировкой время запроса увеличивается до ~1.7 сек. Поле, которое используется для группировки, является основным и индексируется. Где может быть проблема?

Я знаю, что группирование без агрегата считается неверным запросом и плохой практикой, но мне нужны отдельные строки базовой таблицы и я не могу использовать синтаксис DISTINCT.

Сам запрос выглядит так:

SELECT `table_a`.*
FROM   `table_a` 
       LEFT JOIN `table_b` 
              ON `table_b`.`invoice` = `table_a`.`id` 
       LEFT JOIN `table_c` AS `r1` 
              ON `r1`.`invoice_1` = `table_a`.`id` 
       LEFT JOIN `table_c` AS `r2` 
              ON `r2`.`invoice_2` = `table_a`.`id` 
       LEFT JOIN `table_a` AS `i1` 
              ON `i1`.`id` = `r1`.`invoice_2` 
       LEFT JOIN `table_a` AS `i2` 
              ON `i2`.`id` = `r2`.`invoice_1` 
       JOIN `table_d` AS `_u0` 
         ON `_u0`.`id` = 1 
       LEFT JOIN `table_e` AS `_ug0` 
              ON `_ug0`.`user` = `_u0`.`id` 
       JOIN `table_f` AS `_p0` 
         ON ( `_p0`.`enabled` = 1 
              AND ( ( `_p0`.`role` < 2 
                      AND `_p0`.`who` IS NULL ) 
                     OR ( `_p0`.`role` = 2 
                          AND ( `_p0`.`who` = '0' 
                                 OR `_p0`.`who` = `_u0`.`id` ) ) 
                     OR ( `_p0`.`role` = 3 
                          AND ( `_p0`.`who` = '0' 
                                 OR `_p0`.`who` = `_ug0`.`group` ) ) ) ) 
            AND ( `_p0`.`action` = '*' 
                   OR `_p0`.`action` = 'read' ) 
            AND ( `_p0`.`related_table` = '*' 
                   OR `_p0`.`related_table` = 'table_name' ) 
       JOIN `table_a` AS `_e0` 
         ON ( ( `_p0`.`related_id` = 0 
                 OR `_p0`.`related_id` = `_e0`.`id` 
                 OR `_p0`.`related_user` = `_e0`.`user` 
                 OR `_p0`.`related_group` = `_e0`.`group` ) 
               OR ( `_p0`.`role` = 0 
                    AND `_e0`.`user` = `_u0`.`id` ) 
               OR ( `_p0`.`role` = 1 
                    AND `_e0`.`group` = `_ug0`.`group` ) ) 
            AND `_e0`.`id` = `table_a`.`id` 
       JOIN `table_d` AS `_u1` 
         ON `_u1`.`id` = 1 
       LEFT JOIN `table_e` AS `_ug1` 
              ON `_ug1`.`user` = `_u1`.`id` 
       JOIN `table_f` AS `_p1` 
         ON ( `_p1`.`enabled` = 1 
              AND ( ( `_p1`.`role` < 2 
                      AND `_p1`.`who` IS NULL ) 
                     OR ( `_p1`.`role` = 2 
                          AND ( `_p1`.`who` = '0' 
                                 OR `_p1`.`who` = `_u1`.`id` ) ) 
                     OR ( `_p1`.`role` = 3 
                          AND ( `_p1`.`who` = '0' 
                                 OR `_p1`.`who` = `_ug1`.`group` ) ) ) ) 
            AND ( `_p1`.`action` = '*' 
                   OR `_p1`.`action` = 'read' ) 
            AND ( `_p1`.`related_table` = '*' 
                   OR `_p1`.`related_table` = 'table_name' ) 
       JOIN `table_g` AS `_e1` 
         ON ( ( `_p1`.`related_id` = 0 
                 OR `_p1`.`related_id` = `_e1`.`id` 
                 OR `_p1`.`related_user` = `_e1`.`user` 
                 OR `_p1`.`related_group` = `_e1`.`group` ) 
               OR ( `_p1`.`role` = 0 
                    AND `_e1`.`user` = `_u1`.`id` ) 
               OR ( `_p1`.`role` = 1 
                    AND `_e1`.`group` = `_ug1`.`group` ) ) 
            AND `_e1`.`id` = `table_a`.`company` 
WHERE  `table_a`.`date_deleted` IS NULL 
       AND `table_a`.`company` = 4
       AND `table_a`.`type` = 1
       AND `table_a`.`date_composed` >= '2016-05-04 14:43:55' 
GROUP BY `table_a`.`id`

1 ответ

ORs убить производительность.

Этот составной индекс может помочь: INDEX(company, type, date_deleted, date_composed),

LEFT JOIN table_b ON table_b.invoice = table_a.id кажется, ничего не делает, кроме как замедляет обработку. Нет полей table_b используются или SELECTed, Так как это LEFT присоединяйтесь, это не ограничивает вывод. И т.д. Избавьтесь, если это, или обоснуйте это.

То же самое для других объединений.

Что происходит с JOIN а также GROUP BY: Сначала выполняются все объединения; это взрывает количество строк в промежуточной "таблице". Тогда GROUP BY взрывает множество строк.

Один из способов избежать этой медлительности - это сделать

SELECT ...,
    ( SELECT ... ) AS ...,
    ...

вместо JOIN или же LEFT JOIN, Однако это работает, только если в подзапросе есть ноль или одна строка. Обычно это полезно, когда совокупность (например, SUM) можно перенести в подзапрос.

Для дальнейшего обсуждения, пожалуйста, включите SHOW CREATE TABLE,

Другие вопросы по тегам