SQL中的where条件,在数据库中提取与应用浅析

给定一条SQL,如何提取其中的where条件?where条件中的每一个子条件,在SQL执行的过程当中有分别起着什么样的做用?数据库

关系型数据库中的数据组织

关系型数据库中,数据组织涉及到两个最基本的结构:表与索引。测试

表中存储的是完整记录,通常有两种组织形式:堆表(全部的记录无序存储),或者是聚簇索引表(全部的记录,按照记录主键进行排序存储)。spa

索引中存储的是完整记录的一个子集,用于加速记录的查询速度,索引的组织形式,通常均为B+树结构。code

测试排序

让咱们建立一张测试表,为表新增几个索引,而后插入几条记录,最后看看表的完整数据组织、存储结构式怎么样的。索引

create table t1 (a int primary key, b int, c int, d int, e varchar(20));
create index idx_t1_bcd on t1(b, c, d);
insert into t1 values (4,3,1,1,’d’);
insert into t1 values (1,1,1,1,’a’);
insert into t1 values (8,8,8,8,’h’):
insert into t1 values (2,2,2,2,’b’);
insert into t1 values (5,2,3,5,’e’);
insert into t1 values (3,3,2,2,’c’);
insert into t1 values (7,4,5,5,’g’);
insert into t1 values (6,6,4,4,’f’);

t1表的存储结构以下图所示(只画出了idx_t1_bcd索引与t1表结构,没有包括t1表的主键索引):table

idx_t1_bcd索引上有[b,c,d]三个字段(如果InnoDB类的聚簇索引表,idx_t1_bcd上还会包括主键a字段),idx_t1_bcd索引,首先按照b字段排序,b字段相同,则按照c字段排序,以此类推ast

SQL的where条件提取

考虑如下的一条SQL,会走idx_t1_bcd索引基础

select * from t1 where b >= 2 and b < 8 and c > 1 and d != 4 and e != ‘a’;

思考这条SQL的几个关键性问题:select

此SQL,覆盖索引idx_t1_bcd上的哪一个范围?
起始范围:记录[2,2,2]是第一个须要检查的索引项。索引发始查找范围由b >= 2,c > 1决定。
终止范围:记录[8,8,8]是第一个不须要检查的记录,而以前的记录均须要判断。索引的终止查找范围由b < 8决定;

在肯定了查询的起始、终止范围以后,SQL中还有哪些条件可使用索引idx_t1_bcd过滤?
固定了索引的查询范围[(2,2,2),(8,8,8))以后,此索引范围中并非每条记录都是知足where查询条件的。例如:(3,1,1)不知足c > 1的约束;(6,4,4)不知足d != 4的约束。而c,d列,都可在索引idx_t1_bcd中过滤掉不知足条件的索引记录的。
所以,SQL中还可使用c > 1 and d != 4条件进行索引记录的过滤。

在肯定了索引中最终可以过滤掉的条件以后,还有哪些条件是索引没法过滤的?
显而易见,e !='a'这个查询条件,没法在索引idx_t1_bcd上进行过滤,由于索引并未包含e列。e列只在堆表上存在,为了过滤此查询条件,必须将已经知足索引查询条件的记录回表,取出表中的e列,而后使用e列的查询条件e != ‘a’进行最终的过滤。

在理解以上的问题解答的基础上,作一个抽象,可总结出一套放置于全部SQL语句而皆准的where查询条件的提取规则:
可概括为3大类:Index Key (First Key & Last Key),Index Filter,Table Filter。

Index Key

用于肯定SQL查询在索引中的连续范围的查询条件,被称之为Index Key。一个范围包含一个起始与一个终止,所以Index Key也被拆分为Index First Key和Index Last Key,分别用于定位索引查找的起始,以及索引查询的终止条件。

Index First Key
提取规则:从索引的第一个键值开始,检查其在where条件中是否存在,若存在而且条件是=、>=,则将对应的条件加入Index First Key之中,继续读取索引的下一个键值,使用一样的提取规则;若存在而且条件是>,则将对应的条件加入Index First Key中,而后终止Index First Key的提取。
针对上面的SQL,应用这个提取规则,提取出来的Index First Key为(b >= 2, c > 1)。因为c的条件为 >,提取结束,不包括d。

Index Last Key
与Index First Key正好相反,用于肯定索引查询的终止范围。提取规则:从索引的第一个键值开始,检查其在where条件中是否存在,若存在而且条件是=、<=,则将对应条件加入到Index Last Key中,继续提取索引的下一个键值,使用一样的提取规则;若存在而且条件是 < ,则将条件加入到Index Last Key中,同时终止提取;若不存在,一样终止Index Last Key的提取。
针对上面的SQL,应用这个提取规则,提取出来的Index Last Key为(b < 8),因为是 < 符号,所以提取b以后结束。

Index Filter

在Index Key的提取以后固定了索引的查询范围,可是此范围中的项,并不都是知足查询条件的项。在上面的SQL用例中,(3,1,1),(6,4,4)均属于范围中,可是均不知足SQL的查询条件。

Index Filter的提取规则:一样从索引列的第一列开始,检查其在where条件中是否存在:
1 若存在而且where条件仅为 =,则跳过第一列继续检查索引下一列,下一索引列采起与索引第一列一样的提取规则;
2 若where条件为 >=、>、<、<= 其中的几种,则跳过索引第一列,将其他where条件中索引相关列所有加入到Index Filter之中;
3 若索引第一列的where条件包含 =、>=、>、<、<= 以外的条件,则将此条件以及其他where条件中索引相关列所有加入到Index Filter之中;
4 若第一列不包含查询条件,则将全部索引相关条件均加入到Index Filter之中。

针对上面的用例SQL,索引第一列只包含 >=、< 两个条件,所以第一列可跳过,将余下的c、d两列加入到Index Filter中。所以得到的Index Filter为 c > 1 and d != 4 。

Table Filter

Table Filter是最简单,也是提取最为方便的。提取规则:全部不属于索引列的查询条件,均归为Table Filter之中。
针对上面的用例SQL,Table Filter就为 e != 'a'。

总结

SQL语句中的where条件,使用以上的提取规则,最终都会被提取到Index Key (First Key & Last Key),Index Filter与Table Filter之中。 Index First Key,只是用来定位索引的起始范围,在索引第一次Search Path(沿着索引B+树的根节点一直遍历,到索引正确的叶节点位置)时使用,一次判断便可; Index Last Key,用来定位索引的终止范围,所以对于起始范围以后读到的每一条索引记录,均须要判断是否已经超过了Index Last Key的范围,若超过,则当前查询结束; Index Filter,用于过滤索引查询范围中不知足查询条件的记录,所以对于索引范围中的每一条记录,均须要与Index Filter进行对比,若不知足Index Filter则直接丢弃,继续读取索引下一条记录; Table Filter,最后一道where条件的防线,用于过滤经过前面索引的层层考验的记录,判断完整记录是否知足Table Filter中的查询条件,若不知足,跳过当前记录,继续读取索引的下一条记录,若知足,则返回记录,此记录知足了where的全部条件。

相关文章
相关标签/搜索