我们的MySQL(Percona Server)数据库有一个1000万行的大表,有很多慢查询长度超过40秒这样:
SELECT col1, Seller, col3, col4, Id, col5
FROM table1
WHERE Seller = 346761
AND col1 IN (2, 3, 4)
AND col3 = 1
AND col4 NOT IN (5,6,7)
ORDER BY Id DESC
LIMIT 0, 20;
我在Seller
和col1
,col3
,col4
上创建了索引。这些索引是单独的,而不是多列索引(AKA覆盖索引)。 Id
是主键。
EXPLAIN显示MySQL使用主键作为索引查询此sql,而不是关于卖家的索引。
+----+-------------+------------------+-------+--------------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+-------+--------------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | trans_audit_list | index | Seller,AuditStatus | PRIMARY | 8 | NULL | 1483 | Using where |
+----+-------------+------------------+-------+--------------------+---------+---------+------+------+-------------+
当我force index (Seller)
时,它非常快,0.7秒。
我发现如果不使用limit语句,这个查询将使用Seller
索引,会非常快。
为什么MySQL没有在Seller
上使用带有限制语句的索引?
答案 0 :(得分:1)
正如您所遇到的那样,拥有索引并不意味着它将被使用。这适用于每个数据库 - 索引选择取决于查询优化器。正如您所尝试的那样,强制索引并不意味着您将获得最快的结果。
之后,查询缓存可能无法帮助您 - 可以缓存查询计划,因此甚至不会考虑索引。
MySQL每个语句只使用一个索引,所以覆盖索引(多列)是个好主意,但你必须测试它才能确定。
答案 1 :(得分:1)
在ORDER BY DESC
+ LIMIT
条款is a common problematic situation for mysql的优化程序中添加了多个可能的索引情况,强制索引的极少数情况之一实际上可能是合法的。
请注意,您的条款IN (...)
是优化程序的额外麻烦。
如果您确实不需要,我建议您按ID ASC
而不是DESC
订购,以便引擎可以使用主键排序的好处,即ASC
直到进一步实施。
答案 2 :(得分:1)
[Seller]上的非群集索引可能包含太多碎片,并且您的统计信息可能已过期,然后查询优化程序可能无法选择最佳查询计划。如果您还可以为此查询创建覆盖索引(如果用户经常使用此查询),那么检查碎片,更新统计信息或重新构建卖家的非群集索引,这是值得的。创建覆盖索引时,请确保订单是最终用户最常使用的。与您的查询一样,覆盖索引应该在[seller-> col1-> col3-> col4]
上