Oracle复合索引+空值的索引使用问题

Posted Leohahah

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle复合索引+空值的索引使用问题相关的知识,希望对你有一定的参考价值。

昨天在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中可能没这么严格。

以上是关于Oracle复合索引+空值的索引使用问题的主要内容,如果未能解决你的问题,请参考以下文章

Oracle数据库如何提高访问性能

复合唯一键约束,其中一列中包含多个空值

angularjs ng重复svg跳过空值的索引

Oracle 复合索引--转载

Oracle11G_索引

(2.8)Mysql之SQL基础——索引的分类与使用