MySQL 性能:在大表中排序很慢,即使过滤的子集很小
Posted
技术标签:
【中文标题】MySQL 性能:在大表中排序很慢,即使过滤的子集很小【英文标题】:MySQL performance: sort is slow in large table, even though filtered subset is small 【发布时间】:2013-01-28 20:55:43 【问题描述】:我正在尝试调整我的 mysql 查询的性能,但遇到了一个我不理解的问题(因此无法修复)。本质上,如果它们在自己的表中,它可以更快地对 165,000 行进行排序,而不是它们是更大表的子集。
表 fl6 有 200 万行。它在 (departure_out) 上有一个索引 x1。离开_out 是一个日期类型。
以下选择查找 165,916 行。耗时 0.1 秒。
select count(*)
from fl6
where departure_out > "2013-04-01"
and departure_out < "2013-04-05";
以下选择具有相同的 where 子句,但按价格排序。它需要 0.5 秒。 0.4 秒对 165,000 行进行排序。
select id
from fl6
where departure_out > "2013-04-01"
and departure_out < "2013-04-05"
order by price_total limit 1;
我想看看它是否可以更快,所以我创建了一个只包含 165,916 行的小表。然后我做了那种。耗时 0.16 秒。
select id
from fl6_small
order by price_total limit 1;
因此,它可以相当快地对 165,000 行进行排序,但如果它是更大表的子集,则需要两倍以上的时间?我如何让它做到这一点?为什么会有差异?
几件事:我已经尝试在 (price) 和 (departure_out, price) 上设置索引。这没什么区别。无论如何,如果 fl6_small 中的搜索显示即使没有它也可以快速排序,则不需要索引。
编辑:
(编辑了上面的一些行数和时间以匹配用于解释计划的表格)
解释计划:
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------------+
| 1 | SIMPLE | fl6 | range | x1 | x1 | 3 | NULL | 160493 | Using where; Using filesort |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------------+
【问题讨论】:
你的小桌子上有 price_total 的索引吗?如果有一个 mysql 使用它来排序而不是文件排序。 【参考方案1】:您可以使用 EXPLAIN 语句检查查询的瓶颈http://dev.mysql.com/doc/refman/5.0/en/explain.html 还有http://dev.mysql.com/doc/refman/5.0/en/optimization.html
【讨论】:
是的,我试过解释,它只是说它使用department_date的索引。 @user984003:针对哪个查询?两个? 你能发布 EXPLAIN 的结果,还包含完整的 EXPLAIN 查询吗?什么是(出发时间)?这和department_out一样吗? 关于日期时间类型的索引,***.com/questions/2812843/indexing-datetime-in-mysql***.com/questions/4594229/…***.com/questions/4013301/…***.com/questions/5568933/… 哎呀,是的,department_time 应该已经读取了department_out。现在会修复它。【参考方案2】:不同的是,在第一种情况下,MySQL 将创建一个包含 165000 行的临时表,并在没有索引的情况下对它们进行排序。即使价格列有索引,也不能用于排序。
您的小表可能能够使用索引进行排序,因此速度更快。
【讨论】:
只有在查询有WHERE departure_out = xxx
时,(departure_out,price_total) 上的索引才有帮助。它对范围条件没有帮助。
@Vatev 你确定吗?我看不出 MySQL 应该这样做的任何理由。
我不太确定,但我认为它甚至不可能以这种方式使用索引。它适用于=
的原因是所有结果都在索引中的单个子树中。
哦,现在我看到了我的想法的错误;排序与索引不同;它不起作用,你完全正确【参考方案3】:
这可能是由于几个问题。
挑剔点 - 在大表中,您所做的不仅仅是简单的排序,而是首先查找记录,然后进行排序。在您没有按 depature_time 搜索的小桌子上。但这有点作弊,因为表较大,为了知道使用哪个n,它首先必须构建表。如果它被编入索引,那么它不太可能像您的测试显示的那样重要。它仍然花费了 0.5 秒中的 0.1 秒。也可以在小桌子上尝试 where 子句,应该会花费更多时间。如果不是,那么它指向:
第二,*缓存未命中:*
2,000K 记录在您使用的机器上可能远远超过 150K 记录,除非您有一个专门用于 mysql 的专用盒子,这会增加缓存未命中的可能性。即使您将 n^2 排序或更差的记录加载到内存中并且内存对齐,这些未命中可能会造成更大的损失。如果你在一个有很多内存的盒子上运行这些测试,假设所有其他条件都相同,那么差异应该会更小。
【讨论】:
以上是关于MySQL 性能:在大表中排序很慢,即使过滤的子集很小的主要内容,如果未能解决你的问题,请参考以下文章