5.SQL优化之查询范围优化

介绍

范围扫描是指使用索引扫描包含一个或多个索引值内的表行的子集,他可以使用索引中的一部分或者多部分,这里主要是看创建索引时是不是复合索引。

1 单部分索引的范围访问方法

对于单部分索引,索引值间隔可以方便地由WHERE子句中的相应条件表示,表示为范围条件而不是“间隔”。

可以使用单一索引的条件:

  • 对于BTREE和HASH索引,使用=,<=>,IN(),IS NULL或IS NOT NULL运算符时,关键字与常量值的比较是范围条件。
  • 另外,对于BTREE索引,关键字与常量值的比较是使用>,<,> =,<=,BETWEEN,!=或<>运算符时的范围条件,或者LIKE比较时的LIKE比较 是一个不以通配符开头的常量字符串。
  • 对于所有索引类型,多个范围条件与OR或AND组合形成范围条件。

前面描述中的“常量值”表示以下之一:

  • 来自查询字符串的常量
  • 来自同一连接的const或系统表的列
  • 不相关子查询的结果
  • 完全由前面类型的子表达式组成的任何表达式

以下是一些样例

SELECT * FROM t1
  WHERE key_col > 1
  AND key_col < 10;

SELECT * FROM t1
  WHERE key_col = 1
  OR key_col IN (15,18,20);

SELECT * FROM t1
  WHERE key_col LIKE 'ab%'
  OR key_col BETWEEN 'bar' AND 'foo';

在优化器常量传播阶段,一些非常量值可以转换为常量。

MySQL尝试从每个可能索引的WHERE子句中提取范围条件。 在提取过程期间,丢弃不能用于构建范围条件的条件,组合产生重叠范围的条件,并且去除产生空范围的条件。

请考虑以下语句,其中key1是索引列,而nonkey未编入索引:

SELECT * FROM t1 WHERE
  (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR
  (key1 < 'bar' AND nonkey = 4) OR
  (key1 < 'uux' AND key1 > 'z');

关键字key1的提取过程如下:

  1. 提取WHERE子句

     (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR
     (key1 < 'bar' AND nonkey = 4) OR
     (key1 < 'uux' AND key1 > 'z')
    
  2. 删除nonkey = 4和key1 LIKE’%b’,因为它们不能用于索引范围扫描。 删除它们的正确方法是用TRUE替换它们,这样我们在进行范围扫描时不会错过任何匹配的行。 用TRUE替换它们会产生:

     (key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR
     (key1 < 'bar' AND TRUE) OR
     (key1 < 'uux' AND key1 > 'z')
    
  3. 跳出条件的真或假

    • (key1 LIKE ‘abcde%’ OR TRUE) 永为真
    • (key1 < ‘uux’ AND key1 > ‘z’) 永为假

    用常数替换这些条件会产生:

     (key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
    

    删除不必要的TRUE和FALSE常量会产生:

     (key1 < 'abc') OR (key1 < 'bar')
    
  4. 由于key1 < 'bar’肯定满足key1 < ‘abc’,所以将重叠间隔组合成一个会产生用于范围扫描的最终条件

     (key1 < 'bar')
    

通常(并且如前面的示例所示),用于范围扫描的条件比WHERE子句的限制性更小。 MySQL执行额外的检查以过滤掉满足范围条件但不满足完整WHERE子句的行。

范围条件提取算法可以处理任意深度的嵌套AND/OR结构,其输出不依赖于条件在WHERE子句中出现的顺序。

MySQL不支持合并空间索引的范围访问方法的多个范围。

你可能感兴趣的:(MySql)