我不是那么精通MySQL中的索引,并且我很难理解EXPLAIN
输出是如何工作的,以及如何知道我的查询是否被优化。
我有一个相当大的表(1.1M记录),我正在执行以下查询:
SELECT * FROM `Member` this_ WHERE (this_._Temporary_Flag = 0 or this_._Temporary_Flag
is null) and (this_._Deleted = 0 or this_._Deleted is null) and
(this_.Username = 'XXXXXXXX' or this_.Email = 'XXXXXXXX')
ORDER BY this_.Priority asc;
执行需要很长时间,大多数时间在30-60秒之间。 EXPLAIN
查询的输出如下:
id select_type table type possible_keys key key_len ref rows Extra
----------------------------------------------------------------------------------------------------------------------------------
1 SIMPLE this_ ref_or_null _Temporary_Flag,_Deleted,username,email _Temporary_Flag 2 const 33735 Using where; Using filesort
这句话到底意味着什么?这是否意味着可以优化此查询?该表主要包含单列索引。我应该使用EXPLAIN
查询的重要输出是什么?
答案 0 :(得分:0)
它说它选择使用的索引是一个名为_Temporary_Flag的索引(我假设它在_Temporary_Flag列上)。这不是一个很好的索引(它仍然会让它看到33k记录),但它可以在这种情况下使用它。可能值得添加一个涵盖_Temporary_Flag和_Deleted列的索引。
然而,我怀疑这会让事情变得更糟。
一个问题是MySQL只能在查询中的表上使用单个索引。使用的最佳索引可能是用户名,另一个用于电子邮件,但由于您的查询有OR,因此必须选择其中一个。
对索引进行此限制的一种方法是使用两个联合在一起的查询,如下所示: -
SELECT *
FROM `Member` this_
WHERE (this_._Temporary_Flag = 0
or this_._Temporary_Flag is null)
and (this_._Deleted = 0
or this_._Deleted is null)
and this_.Email = 'XXXXXXXX'
UNION
SELECT *
FROM `Member` this_
WHERE (this_._Temporary_Flag = 0
or this_._Temporary_Flag is null)
and (this_._Deleted = 0
or this_._Deleted is null)
and this_.Username = 'XXXXXXXX'
ORDER BY this_.Priority asc;
答案 1 :(得分:0)
http://dev.mysql.com/doc/refman/5.5/en/explain-output.html
解释告诉你MySQL正在做什么,它不一定告诉你,甚至暗示可以做些什么来使事情变得更好。
也就是说,有一些警告标志通常意味着您可以优化查询;在这种情况下,最大的一个是Extra列中出现Using filesort
。
文档解释了在这种情况下会发生什么:
MySQL必须执行额外的传递以找出如何检索行 排序顺序。排序是通过遍历所有行来完成的 连接类型并存储排序键和指向所有行的指针 与WHERE子句匹配的行。然后按键排序和 按排序顺序检索行。
您的案例中的另一个警告标志是使用的key
。虽然在您的情况下不一定如此,但规范化的结构通常需要Username
和Email
的唯一值。
那么,为什么要指定这两件事需要这么长时间?优化器不应该直接进入那些行吗?可能不是,因为您使用OR
指定它们,这使优化器难以使用索引来查找这些行。
相反,优化器决定_Temporary_Flag
查看所有结果,这可能并没有大大缩小结果集,特别是考虑到Explain说看了大约33735行。
因此,假设email
和username
比此键更具选择性,您可以尝试将查询重写为UNION。
SELECT * FROM `Member` this_
WHERE
(this_._Temporary_Flag = 0 or this_._Temporary_Flag
is null)
and
(this_._Deleted = 0 or this_._Deleted is null)
and this_.Email = 'XXXXXXXX'
UNION
SELECT * FROM `Member` this_
WHERE (this_._Temporary_Flag = 0 or this_._Temporary_Flag
is null)
and (this_._Deleted = 0 or this_._Deleted is null)
and
this_.Username = 'XXXXXXXX'
ORDER BY this_.Priority asc;
所以,这些是来自EXPLAIN的几个警示标志:寻找Using filesort
和奇怪的关键选择作为指标,你可以改善一些事情。