通过MySQL上的EXPLAIN查询分析要改进的内容

时间:2013-11-08 08:56:22

标签: mysql indexing database-performance

我不是那么精通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查询的重要输出是什么?

2 个答案:

答案 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。虽然在您的情况下不一定如此,但规范化的结构通常需要UsernameEmail的唯一值。

那么,为什么要指定这两件事需要这么长时间?优化器不应该直接进入那些行吗?可能不是,因为您使用OR指定它们,这使优化器难以使用索引来查找这些行。

相反,优化器决定_Temporary_Flag查看所有结果,这可能并没有大大缩小结果集,特别是考虑到Explain说看了大约33735行。

因此,假设emailusername比此键更具选择性,您可以尝试将查询重写为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和奇怪的关键选择作为指标,你可以改善一些事情。