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
,