介绍
范围扫描是指使用索引扫描包含一个或多个索引值内的表行的子集,他可以使用索引中的一部分或者多部分,这里主要是看创建索引时是不是复合索引。
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的提取过程如下:
- 提取WHERE子句
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR
(key1 < 'bar' AND nonkey = 4) OR
(key1 < 'uux' AND key1 > 'z')
- 删除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')
- 跳出条件的真或假
- (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')
- 由于key1 < 'bar’肯定满足key1 < ‘abc’,所以将重叠间隔组合成一个会产生用于范围扫描的最终条件
(key1 < 'bar')
通常(并且如前面的示例所示),用于范围扫描的条件比WHERE子句的限制性更小。 MySQL执行额外的检查以过滤掉满足范围条件但不满足完整WHERE子句的行。
范围条件提取算法可以处理任意深度的嵌套AND/OR结构,其输出不依赖于条件在WHERE子句中出现的顺序。
MySQL不支持合并空间索引的范围访问方法的多个范围。