我试图了解使用MySQL的SQL查询的性能.
在PK上只有索引时,查询无法在10分钟内完成.
我已经在where子句(时间戳,主机名,路径,类型)中使用的所有列上添加了索引,并且查询现在完成了大约50秒-但是对于看起来不太复杂的查询来说,这似乎仍然很长时间.
因此,我想了解导致查询的原因.我的假设是我的内部子查询以某种方式导致必要的比较数量激增.
涉及两个表:
存储(〜5,000行/ 4.6MB)和计算机(12行,<4k) 查询如下:
SELECT T.hostname, T.path, T.used_pct,
T.used_gb, T.avail_gb, T.timestamp, machines.type AS type
FROM storage AS T
JOIN machines ON T.hostname = machines.hostname
WHERE timestamp = ( SELECT max(timestamp) FROM storage AS st
WHERE st.hostname = T.hostname AND
st.path = T.path)
AND (machines.type = 'nfs')
ORDER BY used_pct DESC
查询的EXPLAIN EXTENDED返回以下内容:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY machines ref hostname,type type 768 const 1 100.00 Using where; Using temporary; Using filesort
1 PRIMARY T ref fk_hostname fk_hostname 768 monitoring.machines.hostname 4535 100.00 Using where
2 DEPENDENT SUBQUERY st ref fk_hostname,path path 1002 monitoring.T.path 648 100.00 Using where
注意第1行的“额外”列包括“使用文件排序”和问题:
MySQL explain Query understanding
指出“使用文件排序是一种排序算法,其中MySQL无法使用索引进行排序,因此无法在内存中进行完整的排序.”
此查询导致性能降低的本质是什么?
为什么MySQL必须为此查询使用“文件排序”?
解决方法:
索引不会填充,而是在您创建索引后立即存在.因此,表上的索引越多,插入和更新就越慢.
第一次查询后,您的查询运行很快,因为查询的整个结果都放入了缓存中.要查看不使用缓存的查询的速度,您可以执行
SELECT SQL_NO_CACHE T.hostname ...
MySQL通常将文件排序用于ORDER BY,或者根据您的情况确定时间戳的最大值. MySQL没有遍历所有可能的值并记住哪个值是最大的,而是对降序的值进行排序并选择第一个值.
那么,为什么查询速度慢?两件事跳进了我的视线.
1)您的子查询
WHERE timestamp = ( SELECT max(timestamp) FROM storage AS st
WHERE st.hostname = T.hostname AND
st.path = T.path)
将针对每个(主机名,路径)进行评估.尝试使用时间戳索引(顺便说一句,我不鼓励诸如关键字/数据类型之类的列的命名).如果仅此一项无济于事,请尝试重写您的查询. MySQL手册中有两个出色的示例:The Rows Holding the Group-wise Maximum of a Certain Column.
2)这是一个小问题,但似乎您正在加入char / varchar字段.数字/ ID更快.