4.SQL优化之Where语句

1 优化Where语句

以下优化适用于使用SELECT语句,但相同的优化适用于DELETE和UPDATE语句中的WHERE子句。

为了优化查询,有时我们可能考虑牺牲程序可读性,但是MySQL在生成执行计划时会对SQL进行改写,所以我们不需要过度改写,尽量保证可读性,只有在性能无法满足的基础上在按照自我理解进行重写SQL,以下是几种MySQL自动进行的SQL改写的例子:

  • 删除不必要的括号:

     	((a AND b) AND c OR (((a AND b) AND (c AND d)))) -> (a AND b AND c) OR (a AND b AND c AND d)
    
  • 常数折叠

      (a<b AND b=c) AND a=5 -> b>5 AND b=c AND a=5
    
  • 恒定条件去除

      (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)-> B=5 OR B=6
    
  • 索引所使用的常数表达式仅计算一次。

  • 没有Where条件的MyISAM和MEMORY存储引擎中统计count(*)时,计算是通过表定义计算获得,所以效率很高。使用一个not null的表达式也可以达到这个效果。

  • 某些SQL是不可能返回rows的,MySQL会提前检测出来然后直接返回。

  • 如果不使用GROUP BY或聚合函数(COUNT(),MIN()等),HAVING将与WHERE合并。

  • 对于每一个表连接,构造一个更简单的Where条件已获得更好的执行计划,尽可能的跳过更多不需要扫描的行。

  • 在执行所有查询之前,首先读取常量表(常量表定义如下):

    • 空表或者只有1行数据的表

    • 与PRIMARY KEY或UNIQUE索引上的WHERE子句一起使用的表,其中所有索引部分与常数表达式进行比较,并定义为NOT NULL。

        SELECT * FROM t WHERE primary_key=1;
        SELECT * FROM t1,t2
          WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
      
  • 通过尝试所有可能性,可以找到加入表格的最佳连接组合。 如果ORDER BY和GROUP BY子句中的所有列都来自同一个表,则在加入时首先首选该表。

  • 如果存在ORDER BY子句和不同的GROUP BY子句,或者ORDER BY或GROUP BY包含连接队列中第一个表以外的表中的列,则会创建临时表。

  • 如果使用SQL_SMALL_RESULT修饰符,MySQL将使用内存中的临时表。

  • 首先查询每个表索引,并使用最佳索引,除非优化程序认为使用表扫描更有效。 在以前,根据最佳索引是否跨越表的30%来使用扫描,但固定百分比不再决定使用索引或扫描之间的选择。 优化器现在更复杂,并且基于其他因素(例如表大小,行数和I/O块大小)进行估算。

  • 在某些情况下,MySQL甚至无需查阅数据文件即可从索引中读取行。 如果索引中使用的所有列都是数字,则仅使用索引树来解析查询。

  • 在输出每一行之前,将跳过与HAVING子句不匹配的行。

一些查询效率较高的SQL样例

SELECT COUNT(*) FROM tbl_name;

SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;

SELECT MAX(key_part2) FROM tbl_name
  WHERE key_part1=constant;

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... LIMIT 10;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;

在索引列是数字的情况下MySQL仅使用索引树解析以下查询

SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;

SELECT COUNT(*) FROM tbl_name
  WHERE key_part1=val1 AND key_part2=val2;

SELECT key_part2 FROM tbl_name GROUP BY key_part1;

以下查询使用索引来按排序顺序检索行,而不需要排序操作:

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... ;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... ;

猜你喜欢

转载自blog.csdn.net/ciqingloveless/article/details/83375335
今日推荐