MySQL查询优化,大表,使用临时filesort

问题描述:

我需要你的帮助,优化查询。一个表是一个有数百万条目的日志表,我试图将我的查询分解为< 1。我的查询应该给出一个全面的概述,因此应该很快。我确信我可以在脚本的帮助下对列表进行多个简单查询。但是,脚本可以做什么,我可以认为 - 我希望至少。也许并不是所有的部分都是最好的,但是我被困在一个使临时表和文件夹(我发现真的很糟糕)的查询中。随着阅读周围我发现使用一些整洁和良好的索引,但现在我卡在一个特定的点。MySQL查询优化,大表,使用临时filesort

让我告诉你它的结果我的最终查询:

SELECT 
    ps.SERVER_ID, 
    ps.FULLNAME, 
    SUM(CASE WHEN pml.ID_TYPE = 3 THEN 1 ELSE 0 END) 'amount_warning', 
    SUM(CASE WHEN pml.ID_TYPE = 4 THEN 1 ELSE 0 END) 'amount_error', 
    SUM(CASE WHEN pml.ID_TYPE = 5 THEN 1 ELSE 0 END) 'amount_alert', 
    SUM(CASE WHEN pml.ID_TYPE = 7 THEN 1 ELSE 0 END) 'amount_critical' 
FROM 
    PAR_SERVER ps 
INNER JOIN 
    PAR_MONITORINGv2_LOG pml ON ps.SERVER_ID = pml.SERVER_ID 
WHERE 
    pml.CREATED_DATE > date_sub(NOW() , INTERVAL 7 DAY) 
GROUP BY 
    ps.SERVER_ID; 

这里是我所得到的:

mysql> [thequeryabove] 
[...] 
59 rows in set (11.69 sec) 

mysql> explain [thequeryabove] 
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys    | key  | key_len | ref      | rows | Extra          | 
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+ 
| 1 | SIMPLE  | pml | ALL | SERVER_ID,SERVER_ID-ID_TYPE | NULL | NULL | NULL      | 4014447 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | ps | eq_ref | PRIMARY      | PRIMARY | 4  | database.pml.SERVER_ID |  1 |            | 
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+ 
2 rows in set (0.00 sec) 

这是我当前的表设置:

mysql> describe PAR_SERVER; 
+----------------+--------------+------+-----+---------+----------------+ 
| Field   | Type   | Null | Key | Default | Extra   | 
+----------------+--------------+------+-----+---------+----------------+ 
| SERVER_ID  | int(255)  | NO | PRI | NULL | auto_increment | 
| FULLNAME  | varchar(255) | YES |  | NULL |    | 
| SHORTNAME  | varchar(255) | YES | MUL | NULL |    | 
+----------------+--------------+------+-----+---------+----------------+ 
3 rows in set (0.00 sec) 

mysql> show indexes from PAR_SERVER; 
+------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| PAR_SERVER |   0 | PRIMARY |   1 | SERVER_ID | A   |   142 |  NULL | NULL |  | BTREE  |   | 
| PAR_SERVER |   1 | shortname |   1 | SHORTNAME | A   |   142 |  NULL | NULL | YES | BTREE  |   | 
+------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
2 rows in set (0.00 sec) 

mysql> select count(*) from PAR_SERVER; 
+----------+ 
| count(*) | 
+----------+ 
|  142 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> describe PAR_MONITORINGv2_LOG; 
+--------------+----------+------+-----+---------+----------------+ 
| Field  | Type  | Null | Key | Default | Extra   | 
+--------------+----------+------+-----+---------+----------------+ 
| ID   | int(11) | NO | PRI | NULL | auto_increment | 
| ID_TYPE  | int(11) | NO | MUL | NULL |    | 
| ID_SERVICE | int(11) | NO | MUL | NULL |    | 
| SERVER_ID | int(11) | NO | MUL | NULL |    | 
| MESSAGE  | tinytext | NO |  | NULL |    | 
| CREATED_DATE | datetime | NO |  | NULL |    | 
+--------------+----------+------+-----+---------+----------------+ 
6 rows in set (0.00 sec) 

mysql> show indexes from PAR_MONITORINGv2_LOG; 
+----------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table    | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+----------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| PAR_MONITORINGv2_LOG |   0 | PRIMARY   |   1 | ID   | A   |  3998188 |  NULL | NULL |  | BTREE  |   | 
| PAR_MONITORINGv2_LOG |   1 | ID_TYPE   |   1 | ID_TYPE  | A   |   7 |  NULL | NULL |  | BTREE  |   | 
| PAR_MONITORINGv2_LOG |   1 | ID_SERVICE  |   1 | ID_SERVICE | A   |   5 |  NULL | NULL |  | BTREE  |   | 
| PAR_MONITORINGv2_LOG |   1 | SERVER_ID   |   1 | SERVER_ID | A   |   66 |  NULL | NULL |  | BTREE  |   | 
| PAR_MONITORINGv2_LOG |   1 | SERVER_ID-ID_TYPE |   1 | SERVER_ID | A   |   66 |  NULL | NULL |  | BTREE  |   | 
| PAR_MONITORINGv2_LOG |   1 | SERVER_ID-ID_TYPE |   2 | ID_TYPE  | A   |   258 |  NULL | NULL |  | BTREE  |   | 
+----------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
6 rows in set (0.00 sec) 

mysql> select count(*) from PAR_MONITORINGv2_LOG; 
+----------+ 
| count(*) | 
+----------+ 
| 3998386 | 
+----------+ 
1 row in set (0.00 sec) 

这里有时间结果一步一步打破我的查询。固定每个部分花费这么长时间后,我可能会逐步加深。但是现在只有运行时间为2.30秒的查询目前对这个问题很有意思。

mysql> SELECT ps.SERVER_ID, ps.FULLNAME FROM PAR_SERVER ps INNER JOIN PAR_MONITORINGv2_LOG pml ON ps.SERVER_ID = pml.SERVER_ID WHERE pml.CREATED_DATE > date_sub(NOW() , INTERVAL 7 DAY) GROUP BY ps.SERVER_ID; 
[...] 
59 rows in set (6.41 sec) 

mysql> explain [thequeryabove] 
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys    | key  | key_len | ref      | rows | Extra          | 
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+ 
| 1 | SIMPLE  | pml | ALL | SERVER_ID,SERVER_ID-ID_TYPE | NULL | NULL | NULL      | 4014788 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | ps | eq_ref | PRIMARY      | PRIMARY | 4  | database.pml.SERVER_ID |  1 |            | 
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+ 
2 rows in set (0.00 sec) 

mysql> SELECT ps.SERVER_ID, ps.FULLNAME FROM PAR_SERVER ps INNER JOIN PAR_MONITORINGv2_LOG pml ON ps.SERVER_ID = pml.SERVER_ID GROUP BY ps.SERVER_ID; 
[...] 
59 rows in set (2.30 sec) 

mysql> explain [thequeryabove] 
+----+-------------+-------+--------+-----------------------------+-----------+---------+---------------------------+---------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys    | key  | key_len | ref      | rows | Extra          | 
+----+-------------+-------+--------+-----------------------------+-----------+---------+---------------------------+---------+----------------------------------------------+ 
| 1 | SIMPLE  | pml | index | SERVER_ID,SERVER_ID-ID_TYPE | SERVER_ID | 4  | NULL      | 4015694 | Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | ps | eq_ref | PRIMARY      | PRIMARY | 4  | database.pml.SERVER_ID |  1 |            | 
+----+-------------+-------+--------+-----------------------------+-----------+---------+---------------------------+---------+----------------------------------------------+ 
2 rows in set (0.00 sec) 

mysql> SELECT pml.SERVER_ID FROM PAR_MONITORINGv2_LOG pml GROUP BY pml.SERVER_ID; 
[...] 
65 rows in set (0.00 sec) 

mysql> explain [thequeryabove] 
+----+-------------+-------+-------+---------------+-----------+---------+------+------+--------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra     | 
+----+-------------+-------+-------+---------------+-----------+---------+------+------+--------------------------+ 
| 1 | SIMPLE  | pml | range | NULL   | SERVER_ID | 4  | NULL | 67 | Using index for group-by | 
+----+-------------+-------+-------+---------------+-----------+---------+------+------+--------------------------+ 
1 row in set (0.00 sec) 

我能够通过定义(SERVER_ID,ID_TYPE)指数为我下面的例子查询来提高查询了很多证实:

mysql> SELECT count(*) 'count_warnings' FROM PAR_MONITORINGv2_LOG pml WHERE pml.SERVER_ID = 191 AND pml.ID_TYPE = 3 GROUP BY pml.SERVER_ID; 
[...] 
1 row in set (0.01 sec) 

mysql> explain [thequeryabove] 
+----+-------------+-------+------+-------------------------------------+-------------------+---------+-------------+-------+-------------+ 
| id | select_type | table | type | possible_keys      | key    | key_len | ref   | rows | Extra  | 
+----+-------------+-------+------+-------------------------------------+-------------------+---------+-------------+-------+-------------+ 
| 1 | SIMPLE  | pml | ref | ID_TYPE,SERVER_ID,SERVER_ID-ID_TYPE | SERVER_ID-ID_TYPE | 8  | const,const | 10254 | Using index | 
+----+-------------+-------+------+-------------------------------------+-------------------+---------+-------------+-------+-------------+ 
1 row in set (0.00 sec) 

我现在被困在最broked下来查询的执行时间很长,为2.30秒。我不知道如何使用没有任何where子句的查询的索引。

+0

A'使用filesort'不一定是“非常糟糕”;但对于大型设备,排序操作可能会对性能产生重大影响。有时,当适当的索引可用时,MySQL可以避免排序操作。可以使用覆盖索引的访问计划('使用索引')通常会提高性能。 – spencer7593

您的查询一定会从PAR_MONITORINGv2_LOG(CREATED_DATE,SERVER_ID,ID_TYPE)加入综合指数受益最大。不过,我建议即使是简单的索引CREATED_DATE也会提高性能很多。