zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

MySQL数据库,SQL的where条件提取

2023-04-18 14:50:07 时间

在有了以上的t1表之后,接下来就可以在此表上进⾏SQL查询了,获取⾃⼰想要的数据。

例如,考虑以下的⼀条SQL:select * from t1 where b >= 2 and b < 8 and c > 1 and d != 4 and e != 'a';

⼀条⽐较简单的SQL,⼀⽬了然就可以发现where条件使⽤到了[b,c,d,e]四个字段,⽽t1表的idxt1bcd索引,恰好使⽤了[b,c,d]这三个字段,那么⾛idxt1bcd索引进⾏条件过滤,应该是⼀个不错的选择。接下来,让我们抛弃数据库的思想,直接思考这条SQL的⼏个关键性问题:

此SQL,覆盖索引idxt1bcd上的哪个范围?

起始范围:记录[2,2,2]是第⼀个需要检查的索引项。索引起始查找范围由b >= 2,c > 1决定。

终⽌范围:记录[8,8,8]是第⼀个不需要检查的记录,⽽之前的记录均需要判断。索引的终⽌查找范围由b < 8决定;

在确定了查询的起始、终⽌范围之后,SQL中还有哪些条件可以使⽤索引idxt1bcd过滤?

根据SQL,固定了索引的查询范围[(2,2,2),(8,8,8))之后,此索引范围中并不是每条记录都是满⾜where查询条件的。例如:(3,1,1)不满⾜c > 1的约束;(6,4,4)不满⾜d != 4的约束。

⽽c,d列,均可在索引idxt1bcd中过滤掉不满⾜条件的索引记录的。

因此,SQL中还可以使⽤c > 1 and d != 4条件进⾏索引记录的过滤。

在确定了索引中最终能够过滤掉的条件之后,还有哪些条件是索引⽆法过滤的?

此问题的答案显⽽易见,e != ‘a’这个查询条件,⽆法在索引idxt1bcd上进⾏过滤,因为索引并未包含e列。e列只在堆表上存在,为了过滤此查询条件,必须将已经满⾜索引查询条件的记录回表,取出表中的e列,然后使⽤e列的查询条件e != ‘a’进⾏最终的过滤。

在理解以上的问题解答的基础上,做⼀个抽象,可总结出⼀套放置于所有SQL语句⽽皆准的where查询条件的提取规则:

所有SQL的where条件,均可归纳为3⼤类

• Index Key (First Key & Last Key)

• Index Filter

• Table Filter

接下来,让我们来详细分析这3⼤类分别是如何定义,以及如何提取的。

1.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的提取;若不存在,同样终⽌Index First Key的提取。

针对上⾯的SQL,应⽤这个提取规则,提取出来的Index First Key为(b >= 2, c > 1)。由于c的条件为 >,提取结束,不包括d。

Index Last Key

Index Last Key的功能与Index First Key正好相反,⽤于确定索引查询的终⽌范围。提取规则:从索引的第⼀个键值开始,检查其在where条件中是否存在,若存在并且条件是=、<=,则将对应条件加⼊到Index Last Key中,继续提取索引的下⼀个键值,使⽤同样的提

取规则;若存在并且条件是 < ,则将条件加⼊到Index Last Key中,同时终⽌提取;若不存在,同样终⽌Index Last Key的提取。针对上⾯的SQL,应⽤这个提取规则,提取出来的Index Last Key为(b < 8),由于是 < 符号,因此提取b之后结束。

2.Index Filter

在完成Index Key的提取之后,我们根据where条件固定了索引的查询范围,但是此范围中的项,并不都是满⾜查询条件的项。在上⾯的SQL⽤例中,(3,1,1),(6,4,4)均属于范围中,但是又均不满⾜SQL的查询条件。

Index Filter的提取规则:同样从索引列的第⼀列开始,检查其在where条件中是否存在:

若存在并且where条件仅为 =,则跳过第⼀列继续检查索引下⼀列,下⼀索引列采取与索引第⼀列同样的提取规则;若where条件为 >=、>、<、<= 其中的⼏种,则跳过索引第⼀列,将其余where条件中索引相关列全部加⼊到Index Filter之中;若索引第⼀列的where条件包含 =、>=、>、<、<= 之外的条件,则将此条件以及其余where条件中索引相关列全部加⼊到Index Filter之中;若第⼀列不包含查询条件,则将所有索引相关条件均加⼊到Index Filter之中。

针对上⾯的⽤例SQL,索引第⼀列只包含 >=、< 两个条件,因此第⼀列可跳过,将余下的c、d两列加⼊到Index Filter中。因此获得的Index Filter为 c > 1 and d != 4 。

3.Table Filter

Table Filter是最简单,最易懂,也是提取最为⽅便的。提取规则:所有不属于索引列的查询条件,均归为Table Filter之中。同样,针对上⾯的⽤例SQL,Table Filter就为 e != ‘a’。

Index Key/Index Filter/Table Filter⼩结

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条件的防线,⽤于过滤通过前⾯索引的层层考验的记录,此时的记录已经满⾜了Index First Key与Index Last Key构成的范围,并且满⾜Index Filter的条件,回表读取了完整的记录,判断完整记录是否满⾜Table Filter中的查询条件,同样的,若不满⾜,跳过当前记录,继续读取索引的下⼀条记录,若满⾜,则返回记录,此记录满⾜了where的所有条件,可以返回给前端⽤户。