MySQL 优化 之 Copying to tmp table on disk
项目中遇到了慢查询问题
Sql语句
SELECT sum(price) AS price, `member_id` FROM `crm_upload` GROUP BY member_id ORDER BY price DESC LIMIT 10;
Explain 之后的结果:
MariaDB [member]> explain SELECT sum(price) as price,`member_id` FROM `crm_upload` WHERE `status` = 1 AND `approved` = 1 AND `consume_time` > '2015-09-10' GROUP BY member_id ORDER BY price desc LIMIT 10; +------+-------------+------------+------+---------------+------+---------+------+--------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+------------+------+---------------+------+---------+------+--------+----------------------------------------------+ | 1 | SIMPLE | crm_upload | ALL | NULL | NULL | NULL | NULL | 310461 | Using where; Using temporary; Using filesort | +------+-------------+------------+------+---------------+------+---------+------+--------+----------------------------------------------+ 1 row in set (0.00 sec)
关于 Using temporary; 手册解释
To resolve the query, MySQL needs to create a temporary table to hold the result. This typically happens if the query
contains GROUP BY and ORDER BY clauses that list columns differently.
大意是,需要一个临时表来暂存查询后的结果,经常会出现在Group By 或者 Order By 中
关于 Using filesort;手册解释
MySQL must do an extra pass to find out how to retrieve the rows in sorted order. The sort is done by going through all rows
according to the join type and storing the sort key and pointer to the row for all rows that match the WHEREclause. The keys then are sorted
and the rows are retrieved in sorted order.
大意是 Mysql 如果想要正常的查找出排序中的数据,需要做一个额外的传递。这个排序将根据join的类型遍历所有的数据,并且存储排序的key。找出匹配到的where条件的数据。
show profile
MariaDB [member]> show profile; +--------------------------------+----------+ | Status | Duration | +--------------------------------+----------+ | starting | 0.000037 | | Waiting for query cache lock | 0.000008 | | init | 0.000006 | | checking query cache for query | 0.000103 | | checking permissions | 0.000011 | | Opening tables | 0.000029 | | After opening tables | 0.000010 | | System lock | 0.000008 | | Table lock | 0.000007 | | After opening tables | 0.000012 | | Waiting for query cache lock | 0.000006 | | After opening tables | 0.000041 | | init | 0.000044 | | optimizing | 0.000016 | | statistics | 0.000244 | | preparing | 0.000116 | | executing | 0.000015 | | Copying to tmp table | 0.000061 | | Copying to tmp table | 0.138350 | | converting HEAP to Aria | 0.003233 | | Creating index | 0.000025 | | Repair by sorting | 0.020695 | | Saving state | 0.000040 | | Creating index | 0.000005 | | converting HEAP to Aria | 0.000070 | | Copying to tmp table on disk | 4.040516 | | Sorting result | 0.020373 | | Sending data | 0.000046 | | end | 0.000003 | | removing tmp table | 0.000838 | | end | 0.000013 | | query end | 0.000008 | | closing tables | 0.000010 | | freeing items | 0.000006 | | updating status | 0.000003 | | Waiting for query cache lock | 0.000002 | | updating status | 0.000715 | | Waiting for query cache lock | 0.000015 | | updating status | 0.000002 | | storing result in query cache | 0.000014 | | logging slow query | 0.000053 | | cleaning up | 0.000017 | +--------------------------------+----------+
可以看到
Copying to tmp table on disk 花费了大量的时间。
结果查找资料后 了解到 发现mysql可以通过变量tmp_table_size和max_heap_table_size来控制内存表大小上限,如果超过上限会将数据写到磁盘上,从而会有物理磁盘的读写操作,导致影响性能。
调整参数配置之后 就不会有这个问题了。
- To set max_heap_table_size to 64M do the following:
SET max_heap_table_size = 1024 * 1024 * 64;
- To set tmp_table_size to 32M do the following:
SET tmp_table_size = 1024 * 1024 * 32;