索引对于数据库的性能有着举足轻重的作用。上一篇文章已经介绍了没有索引的情况下表扫描访问相关知识,本文讨论有索引的情况下数据库系统如何使用索引进行数据访问,内容会比较复杂,强烈建议参看《深入理解DB2索引(Index)》,理解DB2索引的结构,特别是B+树后再阅读本文,否则看起来可能会比较吃力。
由于“基于索引的访问”内容比较庞杂,现在只准备介绍对于一张表使用索引的情况,不考虑多表连接的问题。分三篇进行介绍,这一篇先介绍简单索引访问,下一篇介绍匹配索引扫描和复合索引,最后再介绍一下多索引访问。
基于索引的访问不一定是需要进行扫描的,但是为了表述习惯,这里统称为索引扫描(Index Scan)。
可索引谓词和不可索引谓词(Indexable Predicate and Non-Indexable Predicate)
谓词(Predicate)
对于SQL语句,Where子句后面的条件表达式称为谓词。例如:Select * From EMPLOYEE Where EMPNO=000110 . EMPNO=000110就是谓词。
如果我们在EMPNO列上建立一个索引,那么上述SQL查询就可以使用索引提高查询效率,EMPNO=000110就是可索引谓词。
但是考虑SQL语句:Select * From EMPLOYEE Where EMPNO<>000110 .
即便在EMPNO列上建立了索引,进行该SQL查询时,仍然不能使用该索引,这是因为<>(不等于)操作符无法利用索引B+树结构的优势,如果使用了该索引,不仅要将索引页读入内存进行无意义的查找工作(查找不等于的值就等于所有叶结点都要扫描一遍),还需要将几乎所有的数据页读入内存(凡是EMPNO不等于000110的所有数据页都要读入内存)。还不如直接进行表扫描,省了读入索引页和扫描索引的开销。
这种即便使用了索引也无法带来效率提升的谓词就称为不可索引谓词。
因此,数据库系统优化器只会对可索引谓词考虑使用索引扫描,不可索引谓词即便在相应列上建立了索引也依然使用表扫描。
划分
下表是常见谓词是否可索引谓词的列表:
谓词类型 |
Indexable? |
Stage 1? |
注 释 |
COL = value |
Y |
Y |
16 |
COL = noncol expr |
Y |
Y |
9,11,12,15 |
COL IS NULL |
Y |
Y |
20,21 |
COL op value |
Y |
Y |
13 |
COL op noncol expr |
Y |
Y |
9,11,12,13 |
COL BETWEEN value1 AND value2 |
Y |
Y |
13 |
COL BETWEEN noncol expr1 AND noncol expr2 |
Y |
Y |
9,11,12,13,23 |
value BETWEEN COL1 AND COL2 |
N |
N |
|
COL BETWEEN COL1 AND COL2 |
N |
N |
10 |
COL BETWEEN expression1 AND expression2 |
Y |
Y |
6,7,11,12,13,14 |
COL LIKE 'pattern' |
Y |
Y |
5 |
COL IN (list) |
Y |
Y |
17,18 |
COL <> value |
N |
Y |
8,11 |
COL <> nocol expr |
N |
Y |
8,11 |
COL IS NOT NULL |
Y |
Y |
21 |
COL NOT BETWEEN value1 AND value2 |
N |
Y |
|
谓词类型 |
Indexable? |
Stage 1? |
注释 |
COL NOT BETWEEN noncol expr1 AND noncol expr2 |
N |
Y |
|
value NOT BETWEEN COL1 AND COL2 |
N |
N |
|
COL NOT IN (list) |
N |
Y |
|
COL NOT LIKE ' char' |
N |
Y |
5 |
COL LIKE '%char' |
N |
Y |
1,5 |
COL LIKE '_char' |
N |
Y |
1,5 |
COL LIKE host variable |
Y |
Y |