令人困惑的MySQL解释结果

时间:2018-03-10 17:13:38

标签: mysql performance

我目前正试图找出哪个查询实际上更好地利用了索引,哪些查询会更快(这两件事情并不总是重合)。

我已经运行了两次相同的查询,但是索引列被拖曳以最大限度地提高性能。

INDEX(type, finalized_on, user_id, date_applied)

mysql> explain 
select user_id
     , sum(amount) amount 
  from user_accounts_payable force index (type_date_finalized_user) 
 where type=1 
   and date_applied between '2018-01-01' and '2019-01-01' 
   and finalized_on is null 
 group 
  by user_id;
+----+-------------+-----------------------+------+----------------------------------------------------------------------------+--------------------------+---------+-------------+-------+------------------------------------+
| id | select_type | table                 | type | possible_keys                                                              | key                      | key_len | ref         | rows  | Extra                              |
+----+-------------+-----------------------+------+----------------------------------------------------------------------------+--------------------------+---------+-------------+-------+------------------------------------+
|  1 | SIMPLE      | user_accounts_payable | ref  | type_user_date_finalized,type_user_finalized_date,type_date_finalized_user | type_date_finalized_user | 10      | const,const | 59720 | Using index condition; Using where |
+----+-------------+-----------------------+------+----------------------------------------------------------------------------+--------------------------+---------+-------------+-------+------------------------------------+
1 row in set

现在使用INDEX(type, finalized_on, date_applied, user_id)

mysql> explain select user_id, sum(amount) amount from user_accounts_payable force index (type_date_finalized_user) where type=1 and date_applied between '2018-01-01' and '2019-01-01' and finalized_on is null group by user_id;
+----+-------------+-----------------------+-------+----------------------------------------------------------------------------+--------------------------+---------+------+------+--------------------------------------------------------+
| id | select_type | table                 | type  | possible_keys                                                              | key                      | key_len | ref  | rows | Extra                                                  |
+----+-------------+-----------------------+-------+----------------------------------------------------------------------------+--------------------------+---------+------+------+--------------------------------------------------------+
|  1 | SIMPLE      | user_accounts_payable | range | type_user_date_finalized,type_user_finalized_date,type_date_finalized_user | type_date_finalized_user | 13      | NULL | 3243 | Using index condition; Using temporary; Using filesort |
+----+-------------+-----------------------+-------+----------------------------------------------------------------------------+--------------------------+---------+------+------+--------------------------------------------------------+
1 row in set

第二个查询清楚地使用了更多的索引,我可以看到key_len(13 vs 10),它匹配的rows的数量更少(3243 vs 59720)。

让我失望的是type的{​​{1}},refextra列。

在第二个查询中,我看到了"使用临时;使用filesort"它不会出现在第一个查询中。 EXPLAINtype而不是rangeref应该比ref更快),range列为{{1}而不是ref

那么......哪个更好地利用了索引?

1 个答案:

答案 0 :(得分:2)

第一个能够使用GROUP BY user_id的索引,从而避免排序(tmp + filesort)。但是,它必须跳过日期不在范围内的任何行,因此行数较大。

第二个使用日期范围,因此行数较少,但必须进行排序。

如果您有两个索引,未使用FORCE INDEX,则优化程序可能根据特定日期范围动态选择更好的索引。 (但我对此表示怀疑。)无论如何,您的查询是一种情况,即优化程序根本没有足够的统计数据来始终"做正确的事情"。

请注意"使用临时;使用filesort" 经常快速,简单,在RAM中的qsort - 没有临时表,没有磁盘命中。 (我这样说是为了提醒读者不要害怕这句话。

如果您将amount添加到任一索引的 end ,您将获得"使用索引",这意味着它是"覆盖&#34 ;索引,它将(非常粗略地)运行两倍。

"使用索引条件"是无关的;这意味着引擎对WHERE进行了一些评估。