使用filesort和temp表区别(或分组)

时间:2013-11-08 23:25:13

标签: mysql indexing group-by distinct

我知道有相似的问题,但我有一个特定的查询/问题为什么这个查询

EXPLAIN SELECT DISTINCT RSubdomain FROM R_Subdomains WHERE EmploymentState IN (0,1) AND RPhone='7853932120' 

给我这个输出解释

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  RSubdomains index   NULL    RSubdomain  767 NULL    3278    Using where

with和RSubdomains上的索引

但如果我在EmploymentState / RPhone上添加综合索引

我从解释

获得此输出
id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  RSubdomains range   EmploymentState EmploymentState 67  NULL        2   Using where; Using temporary

如果我在RSubdomains上删除了distinct,它会从explain输出中删除Using temp ...但是我没有得到的是为什么,当我添加复合键(并保持密钥在RSubdomain上)时,最后使用临时表,哪个索引模式更好?我看到在组合键上扫描的行数要少得多,但查询的类型范围也很慢。

1 个答案:

答案 0 :(得分:1)

问:为什么......使用临时表最终会结束?

MySQL正在对索引进行范围扫描(即读取索引块)以定位满足谓词的行(WHERE子句)。然后MySQL必须从基础表中查找RSubdomain列的值(它在索引中不可用)。为了消除重复,MySQL需要扫描检索到的RSubdomain的值。 “使用临时”表示MySQL正在实现结果集,该结果集在后续步骤中处理。 (可能,这是检索到的RSubdomain值的集合;给定DISTINCT,MySQL实际上可能正在创建一个临时表,其中RSubdomain作为主键或唯一键,并且只插入非重复值。

在第一种情况下,看起来行正在按RSubdomain顺序检索(可能是群集密钥中的第一列)。这意味着MySQL无需比较所有RSubdomain值的值;它只需要检查上次检索的值是否与当前检索的值匹配,以确定是否可以“跳过”该值。

问:这里哪个索引架构更好?

查询的最佳索引可能是覆盖索引:

... ON R_Subdomains (RPhone, EmploymentState, RSubdomain)

但是只有3278行,您不太可能看到任何性能差异。

后续

不幸的是,MySQL没有提供其他RDBMS中提供的检测类型(比如Oracle事件10046 sql跟踪,它提供了资源和等待的实际时间。)

由于MySQL在可用时选择使用索引,这可能是最有效的计划。为了获得最佳效率,我将执行OPTIMIZE TABLE操作(对于InnoDB表和具有动态格式的MyISAM表,如果有大量DML更改,尤其是DELETE和UPDATE修改行的长度......)至少,它将确保索引统计数据是最新的。

您可能希望比较执行GROUP BY而不是DISTINCT的等效语句的计划,即

SELECT r.RSubdomain
  FROM R_Subdomains r
 WHERE r.EmploymentState IN (0,1)
   AND r.RPhone='7853932120'
 GROUP
    BY r.Subdomain

为了获得最佳性能,我将使用RPhone作为主要栏目的覆盖指数;这是基于对RPhone列的基数(接近唯一值)的假设,与EmploymentState列中的几个不同值相对。覆盖索引将提供最佳性能...即最快消除需要检查的行。

但同样,只有几千行,很难看出任何性能差异。如果查询正在检查数百万行,那么当您可能看到差异时,良好性能的关键将限制需要检查的行数。