如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033
环境:
MySQL版本:5.5.15
操作系统:windows
本文讨论范围的优化。
范围访问方法使用一个单独的索引来取回一个表记录的子集, 包含在一部分或者多个部分, 索引值区间。它可用于
单部分或者多部分 索引,下面的章节给出:
范围访问方法使用单个索引来检索包含在一个或多个索引值区间内的表行的子集。 它可以用于单部分或多部分索引。 以下部分详细介绍了如何从WHERE子句中提取区间。
##1.单部分索引的范围访问方法
对于单部分索引,可以通过WHERE子句中的相应条件方便地表示索引值区间,表示为范围条件(range condition)而不是“区间”(interval )。
单个部分索引的范围条件(range condition)定义如下:
对于BTREE和HASH索引,使用=,<=>,IN(),IS NULL或IS NOT NULL运算符时,关键部分与常量值的比较是一个范围条件(range condition)。
另外,对于BTREE索引,当使用>,<=>,<=,BETWEEN,!=或<>运算符或LIKE比较(如果LIKE的参数是一个不以通配符开始的常量字符串)时,关键部分与常量值的比较是一个范围条件(range condition)。
对于所有的索引类型,OR和AND多个范围条件(range condition)的融合形成一个范围条件(range condition)。
EXPLAIN输出的类型列描述如何连接表,这里只介绍和本内容相关的部分:
const
该表至多有一个匹配的行,在查询开始时读取。 由于只有一行,因此该行中列的值可以被优化器的其余部分视为常量。 const表非常快,因为它们只读一次。
system
该表只有一行(=系统表)。 这是const连接类型的特例。
3.一个不相关的子查询的结果
4.任何表达式完全由前面的类型的子表达式组成
以下是在WHERE子句中使用范围条件(range condition)查询的一些示例:
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子句中为每个可能的索引提取范围条件(range condition)。 在提取过程中,不能用于构建范围条件(range condition)的条件被删除,产生重叠范围的条件被合并,产生空的范围的条件被去除。
考虑下面的语句,其中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');
范围条件(range condition)的提取过程如下:
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.不能用于构建范围条件(range condition)的条件被删除
删除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) 总是true
(key1 < ‘uux’ AND key1 > ‘z’) 总是false
用常量代替这些条件产生:
(key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
删除不必要的TRUE和FALSE常量会产生:
(key1 < 'bar')
一般来说(和前面的例子一样),用于范围扫描的条件与WHERE子句相比限制性更小。 MySQL执行额外的检查来筛选满足范围条件但不满足WHERE子句的行。
范围条件提取算法可以处理任意深度的嵌套AND / OR结构,其输出不依赖于条件出现在WHERE子句中的顺序。
MySQL不支持为空间索引的范围访问方法合并多个范围。 要解决此限制,可以使用具有相同SELECT语句的UNION,不同之处在于您将每个空间谓词放在不同的SELECT中。
多部分索引的范围条件是单部分索引的范围条件的扩展。 多部分索引的范围条件将索引行限制在一个或多个关键元组间隔内。 键元组间隔是通过使用索引中的排序在一组关键元组上定义的。
例如,考虑定义为key1(key_part1,key_part2,key_part3)的多部分索引以及按键顺序列出的以下一组键元组:
key_part1 key_part2 key_part3
NULL 1 'abc'
NULL 1 'xyz'
NULL 2 'foo'
1 1 'abc'
1 1 'xyz'
1 2 'abc'
2 1 'aaa'
条件key_part1 = 1定义了这个区间(interval ):
(1,-inf,-inf) <= (key_part1,key_part2,key_part3) < (1,+inf,+inf)
区间(interval )覆盖了前面数据集中的第4,5和6个元组,并且可以被范围访问方法使用。
相比之下,条件key_part3 ='abc’没有定义单个区间(interval ),不能被范围访问方法使用。
以下说明更详细地指出了范围条件(range condition)如何适用于多部分索引。
key_part1 cmp const1
AND key_part2 cmp const2
AND ...
AND key_partN cmp constN;
在这里,const1,const2,…是常量,cmp是=,<=>或IS NULL比较运算符之一,条件覆盖所有索引部分。(也就是说,有N个条件,一个用于N部分索引的每个部分)。例如,以下是三部分HASH索引的范围条件:
key_part1 = 1 AND key_part2 IS NULL AND key_part3 = 'foo'
有关常量值的定义,请到本文第一节中的注意事项查看。
只要比较运算符是=,<=>或IS NULL,优化器就会尝试使用其他关键部分来确定区间(interval )。 如果运算符是>,<,> =,<=,!=,<>,BETWEEN或LIKE,则优化程序使用它,但不考虑更多关键部分。 对于下面的表达式,优化器在第一个比较中使用=。 它也使用> =从第二个比较,但不考虑更多的关键部分,不使用第三个比较的区间构造:
key_part1 = 'foo' AND key_part2 >= 10 AND key_part3 > 10
单个区间(interval ):
('foo',10,-inf) < (key_part1,key_part2,key_part3) < ('foo',+inf,+inf)
创建的区间(interval )可能包含比初始条件更多的行。 例如,前面的区间(interval )包括不符合原始条件的值(‘foo’,11,0)。
(key_part1 = 1 AND key_part2 < 2) OR (key_part1 > 5)
区间(interval )为:
(1,-inf) < (key_part1,key_part2) < (1,2)
(5,-inf) < (key_part1,key_part2)
在这个例子中,第一行的区间(interval )使用一个关键部分的左边界和两个关键部分的右边界。 第二行的区间(interval )只使用一个关键部分。 EXPLAIN输出中的key_len列表示所用key前缀的最大长度。
在某些情况下,key_len可能表示使用了关键部分,但这可能不是您所期望的。 假设key_part1和key_part2可以是NULL。 然后,key_len列显示以下情况下的两个关键部件长度:
key_part1 >= 1 AND key_part2 < 2
但是,事实上,条件转换为:
key_part1 >= 1 AND key_part2 IS NOT NULL
单部分索引的范围访问方法描述了如何执行优化来合并或消除单部分索引的范围条件的间隔。 在多部分索引的范围条件下执行类似的步骤。
Reference:
https://dev.mysql.com/doc/refman/5.5/en/range-optimization.html
https://dev.mysql.com/doc/refman/5.5/en/explain-output.html
觉得文章对你有帮助,可以扫描二维码捐赠给博主,谢谢!
如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033