MySQL组通过杀死查询性能

时间:2016-06-06 08:37:56

标签: mysql innodb

我有MySQL查询当前选择和连接13个表,最后分组~60k行。没有分组的查询需要〜0ms,但是对于分组,查询时间增加到~1.7秒。用于分组的字段是主要字段并已编制索引。问题出在哪里?

我知道group by without aggregate被认为是无效查询和不良做法,但我需要不同的基表行,不能使用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 个答案:

答案 0 :(得分:0)

ORs杀戮表现。

此综合索引可能会有所帮助:INDEX(company, type, date_deleted, date_composed)

LEFT JOIN table_b ON table_b.invoice = table_a.id似乎除了减慢处理速度之外什么也没做。没有使用table_b字段或SELECTed。由于它是LEFT连接,因此不会限制输出。等等。摆脱它,或证明它是正确的。

同样适用于其他联盟。

JOINGROUP BY会发生什么:首先,执行所有连接;这会爆炸中间“表”中的行数。然后GROUP BY会破坏行集。

一种避免这种爆炸性内爆缓慢的技术是

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

而不是JOINLEFT JOIN。但是,仅当子查询中有零行或一行时才有效。通常,当聚合(例如SUM)可以移动到子查询中时,这是有益的。

如需进一步讨论,请加入SHOW CREATE TABLE