【问题标题】:Why does select statement influence query execution and performance in MySQL?为什么 select 语句会影响 MySQL 中的查询执行和性能?
【发布时间】:2010-09-22 14:53:37
【问题描述】:

我遇到了 MySQL 的一个奇怪行为。 查询执行(即explain [QUERY]所示的索引的使用)和执行所需的时间取决于where子句的元素。

这是出现问题的查询:

select distinct
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1, ent_leng el1, rel_c r1, _tax_c t1, rel_c r2, _tax_c t2
where el1.fk_ent=e1.idx
and r1.fk_ent=e1.idx and ((r1.fk_cat=43) or (r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43))
and r2.fk_ent=e1.idx and ((r2.fk_cat=10) or (r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))

对应的解释输出为:

| id | select_type | table | type   | possible_keys           | key     | key_len | ref           | rows  | Extra                       
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
|  1 | SIMPLE      | el1   | index  | fk_ent                  | fk_ent  | 4       | NULL          | 15002 | Using index; Using temporary
|  1 | SIMPLE      | e1    | eq_ref | PRIMARY                 | PRIMARY | 4       | DB.el1.fk_ent |     1 | Using index
|  1 | SIMPLE      | r1    | ref    | fk_ent,fk_cat,fks       | fks     | 4       | DB.e1.idx     |     1 | Using where; Using index
|  1 | SIMPLE      | r2    | ref    | fk_ent,fk_cat,fks       | fks     | 4       | DB.el1.fk_ent |     1 | Using index
|  1 | SIMPLE      | t1    | index  | fk_cat1,fk_cat2,fk_cats | fk_cats | 8       | NULL          |    69 | Using where; Using index; Distinct; 
|    |             |       |        |                         |         |         |               |       | Using join buffer
|  1 | SIMPLE      | t2    | index  | fk_cat1,fk_cat2,fk_cats | fk_cats | 8       | NULL          |    69 | Using where; Using index; Distinct;  
                                                                                                          | Using join buffer

如您所见,单列索引与它所属的列同名。我还添加了一些无用的索引以及使用的索引,只是为了查看它们是否会更改执行(它们不会)。

执行大约需要 4.5 秒。

当我将列 entl1.name 添加到选择部分(没有其他更改)时,el1 中的索引 fk_ent 不能再使用:

| id | select_type | table | type   | possible_keys           | key     | key_len | ref           | rows  | Extra                       
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
|  1 | SIMPLE      | el1   | ALL    | fk_ent                  |  NULL   | NULL    | NULL          | 15002 | Using temporary

现在执行大约需要 8.5 秒。

我一直认为查询的select部分不会影响引擎对索引的使用,不会以这种方式影响性能。

省略属性不是解决方案,我必须选择更多属性。 更糟糕的是,使用形式的查询更加复杂,这使得性能问题成为一个大问题。

所以我的问题是: 1)这种奇怪行为的原因是什么? 2) 如何解决性能问题?

感谢您的帮助! 格雷德

【问题讨论】:

    标签: sql mysql indexing query-performance


    【解决方案1】:

    这是 DISTINCT 限制。您可以将其视为另一个 WHERE 限制。当您更改选择列表时,您实际上是在更改 DISTINCT 限制的 WHERE 子句,现在优化器决定无论如何都必须进行表扫描,所以它可能不使用您的索引。

    编辑:

    不确定这是否有帮助,但如果我正确理解您的数据,我认为您可以像这样摆脱 DISTINCT 限制:

    select
    e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
    from ent e1
      Inner Join ent_leng el1 ON el1.fk_ent=e1.idx
      Inner Join rel_c r1 ON r1.fk_ent=e1.idx
      Inner Join rel_c r2 ON r2.fk_ent=e1.idx
    where 
     ((r1.fk_cat=43) or Exists(Select 1 From _tax_c t1 Where r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43)) 
     and 
     ((r2.fk_cat=10) or Exists(Select 1 From _tax_c t2 Where r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))
    

    【讨论】:

    • 听起来很合理。但这不是问题的解决方案(我要么必须处理巨大的、准冗余的结果集,要么使用复杂的索引)。而且,奇怪的是,删除 DISTINCT 不会改变 EXPLAIN 输出,也不会加快查询速度,正如我刚刚检查过的那样。
    • 刚刚测试过:您的查询似乎与我的查询产生了相同的结果——而且速度要快得多!谢谢!我认为我必须深入研究 SQL 才能正确使用它。
    【解决方案2】:

    如果可能,MySQL 将从索引中返回数据,从而避免加载整行。这样,选中的列就可以影响索引的选择。

    考虑到这一点,将所有必需的列添加到索引中会更有效,尤其是在只选择一小部分列的情况下。

    【讨论】:

      猜你喜欢
      • 2015-05-04
      • 1970-01-01
      • 2013-06-20
      • 2012-06-25
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      相关资源
      最近更新 更多