欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据库联合索引+空值的索引使用问题

程序员文章站 2022-06-25 20:19:21
...

昨天在QQ群里讨论一个SQL优化的问题,语句大致如下:

select A,min(B) from table group by A;
--A,B都没有not null约束,A列无空值,B列有空值。
--存在复合索引IX_TEST(A,B)

于是手动测试,先看Oracle,环境采用Oracle自带的scott用户下的emp表。

1.首先查看如下语句的执行计划(此时表只有主键索引):

数据库联合索引+空值的索引使用问题

2.添加IX_TEST(deptno,comm)后查看执行计划:

数据库联合索引+空值的索引使用问题

数据库联合索引+空值的索引使用问题

发现依然是全表扫描。

3.为deptno列添加非空约束后再次查看执行计划:

数据库联合索引+空值的索引使用问题

数据库联合索引+空值的索引使用问题

SQL Server的相关测试流程基本一致。

Tom在《Expert one on Oracle》中说:Oracle数据库中,除位图索引和聚簇索引外,单列Btree索引节点是不存储空值的。联合索引只要有一个列不为空,Btree节点就会存储索引键值。

在本例中我们创建了(deptno,comm)的联合索引,如果deptno没有非空约束优化器选择全表扫描,如果有非空约束优化器选择索引全扫描。说明添加非空约束后Oracle认为所有的记录都已经被包含在了索引中因此无需全表扫描。

因此在Oracle中一定要为联合索引的首列设置非空约束。

4.MySQL测试

在MySQL中这个问题稍微复杂一点,因为MySQL的NULL值和空字符是有区别的,本文只测试innodb存储引擎(MySQL5.7.22版本)。

首先把SCOTT的数据从oracle完全搞到MySQL,除了EMP表外其他3个表的使用navicat即可同步,EMP表由于HIREDATE的日期类型,需要先自己在MySQL端创建表然后使用PLSQL Developer导出SQL插入语句然后将其在MySQL端执行,如下是当前的EMP表数据:

数据库联合索引+空值的索引使用问题

创建索引后结果如下:

数据库联合索引+空值的索引使用问题

可见在Mysql Innodb中无论复合索引首列是否存在非空约束,都会使用索引,这点与Oracle不同。

那么innodb中如果索引中存在NULL值,还会使用索引吗?继续测试:

数据库联合索引+空值的索引使用问题

 数据库联合索引+空值的索引使用问题

可以看到存在NULL值,innodb也会走索引,那么空字符呢?

继续测试发现无论字符类型的列中存储的是NULL还是空字符''都是会走索引的。

在3大关系型数据库中,B+tree索引结构最为明了的反而是SQL Server,从dump出来的索引页我们可以看到SQL Server的Btree索引是存储null值的,即便全部都是空也会存储空值+主键书签。而且以上涉及的SQL全部会使用到联合索引,这点不但方便使用而且也很容易想通。

更多更详细的测试有待继续补充。

最后:Oracle数据库列能添加非空约束的一定要添加,MySQL、SQLServer中可能没这么严格。