oracle索引空字段,一文搞懂Oracle中索引和空值的恩恩怨怨

2024-02-10 06:30

本文主要是介绍oracle索引空字段,一文搞懂Oracle中索引和空值的恩恩怨怨,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在日常的工作中,空值总是有特殊的身份,它和索引之间也是“恩怨”颇多。

(1)有时候创建索引会因为空值出现一些奇怪的结果。

(2)有时候一个简单的查询因为空值却走不了索引。

我们来简单地模拟一下这些问题。

首先创建一个空表,注意,对于ID列我们是加了NOT NULL约束的。

SQL> create table index_test(id number not null,name varchar2(30) ) ;

Table created.

创建一个唯一性索引,包含了ID和name列。

SQL> create unique index inx_test on index_test(id,name);

Index created.

这个时候我们对表index_test插入数据。因为name列没有非空约束,所以可以为空。注意第一条insert语句,如果插入空串也会作为NULL来处理。

SQL> insert into index_test values(2,'');

1 row created.

SQL> insert into index_test values(1,'a');

1 row created.

SQL> insert into index_test values(3,null);

1 row created.

收集一下统计信息。

exec dbms_stats.gather_table_stats(user,'INDEX_TEST');

查看查询的执行计划,如下。

SQL> select *from index_test where id is not null;

Execution Plan

----------------------------------------------------------

Plan hash value: 4273605835

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 3 | 12 | 1 (0)| 00:00:01 |

| 1 | INDEX FULL SCAN | INX_TEST | 3 | 12 | 1 (0)| 00:00:01 |

-----------------------------------------------------------------------------

对于这个查询可能没什么感觉,走了全索引扫描。我们在查询条件中添加了id is not null的条件,其实ID列已经存在非空约束了,所以这个过滤条件可有可无。

我们来看看不加过滤条件的情况,还是走了全索引扫描,如下。

SQL> select *from index_test;

Execution Plan

----------------------------------------------------------

Plan hash value: 4273605835

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 3 | 12 | 1 (0)| 00:00:01 |

| 1 | INDEX FULL SCAN | INX_TEST | 3 | 12 | 1 (0)| 00:00:01 |

-----------------------------------------------------------------------------

取消ID列的非空约束。

SQL> alter table index_test modify(id number null);

Table altered.

再次查询执行计划,发现走了全表扫描。

SQL> select *from index_test;

Execution Plan

----------------------------------------------------------

Plan hash value: 356488860

-----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 3 | 12 | 3 (0)| 00:00:01 |

| 1 | TABLE ACCESS FULL| INDEX_TEST | 3 | 12 | 3 (0)| 00:00:01 |

-----------------------------------------------------------------------------

添加非空的过滤条件,又可以走索引了。

SQL> select *from index_test where id is not null;

Execution Plan

----------------------------------------------------------

Plan hash value: 4273605835

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 3 | 12 | 1 (0)| 00:00:01 |

|* 1 | INDEX FULL SCAN | INX_TEST | 3 | 12 | 1 (0)| 00:00:01 |

-----------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("ID" IS NOT NULL)

那么问题来了,索引对于空值好像总是有些特殊,下面来看看空值在索引中的一些细节。

SQL> set autot off

这个时候表index_test的索引还是唯一性索引,尝试插入一些值来对比一下。

如果插入name列为NULL,可以正常插入。

SQL> insert into index_test values(1,null);

1 row created.

如果插入ID列为NULL,也可以正常插入。因为我们取消了ID列的非空约束。

SQL> insert into index_test values(null,1);

1 row created.

插入ID、name列为NULL,这个时候竟然可以正常插入。

SQL> insert into index_test values(null,null);

1 row created.

再尝试一条,竟然还可以正常插入。

SQL> insert into index_test values(null,null);

1 row created.

我们再来试试空串的情况,发现结果和NULL是一致的,都可以插入。

SQL> insert into index_test values('','');

1 row created.

SQL> insert into index_test values('','');

1 row created.

简单分析一下索引,来看看空值在索引中的存储情况。

SQL> analyze index inx_test validate structure;

Index analyzed.

首先来看index_test中的数据情况,因为有些行存在空值,把rownum打印出来方便查看。

SQL> select rownum,id,name from index_test;

ROWNUM ID NAME

---------- ---------- ------------------------------

1 2

2 1 a

3 3

4 1

5 1

6

7

8

9

9 rows selected.

一共有9行数据,索引只有5行,最后4行都不在索引中。这也就基本能够说明为什么上面的查询条件中id is NOT NULL有时候走索引,有时候又不走索引。

至于为什么可以成功插入ID、name列为空的行,是因为对于Oracle来说,(NULL,NULL)和(NULL,NULL)是不同的,NULL值总是介于一种很模糊的状态。

SQL> select name,lf_rows from index_stats;

NAME LF_ROWS

------------------------------ ----------

INX_TEST 5

对表index_test中的数据进行统计,NULL值的统计结果是包含了NULL和空串。

SQL> select id,name,count(*)from index_test group by id,name ;

ID NAME COUNT(*)

---------- ------------------------------ ----------

1 1

4

1 a 1

3 1

2 1

1 1

6 rows selected.

此外,在平时的工作中,如果需要对某个表创建索引,就需要考虑NULL值的情况,为了使得索引能够正常启用,我们需要索引列中至少有一列存在非空约束。

就如下面的情况,我们已经存在唯一性索引,但是因为b树索引不会存储NULL的条目,所以对表中已有的空值就需要使用全表扫描。

SQL> set autot trace exp

SQL> select id,name from index_test;

Execution Plan

----------------------------------------------------------

Plan hash value: 356488860

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 3 | 12 | 3 (0)| 00:00:01 |

| 1 | TABLE ACCESS FULL| INDEX_TEST | 3 | 12 | 3 (0)| 00:00:01 |

-----------------------------------------------------------------------------

如果需要输出非空的数据,加入is NOT NULL的过滤条件,索引就能够正常启用。

select id,name from index_test where id is not null

Execution Plan

----------------------------------------------------------

Plan hash value: 4273605835

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 3 | 12 | 1 (0)| 00:00:01 |

|* 1 | INDEX FULL SCAN | INX_TEST | 3 | 12 | 1 (0)| 00:00:01 |

-----------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("ID" IS NOT NULL)

193230fa0641c2bf05b6c2f7ce138177.png

小结: Oracle中的空值会影响索引扫描,会出现一些潜在的性能问题,在表设计中,字段如果可以设置为非空,就绝对不要使用null值。

举报/反馈

这篇关于oracle索引空字段,一文搞懂Oracle中索引和空值的恩恩怨怨的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/696367

相关文章

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成

MySQL 索引简介及常见的索引类型有哪些

《MySQL索引简介及常见的索引类型有哪些》MySQL索引是加速数据检索的特殊结构,用于存储列值与位置信息,常见的索引类型包括:主键索引、唯一索引、普通索引、复合索引、全文索引和空间索引等,本文介绍... 目录什么是 mysql 的索引?常见的索引类型有哪些?总结性回答详细解释1. MySQL 索引的概念2

Oracle迁移PostgreSQL隐式类型转换配置指南

《Oracle迁移PostgreSQL隐式类型转换配置指南》Oracle迁移PostgreSQL时因类型差异易引发错误,需通过显式/隐式类型转换、转换关系管理及冲突处理解决,并配合验证测试确保数据一致... 目录一、问题背景二、解决方案1. 显式类型转换2. 隐式转换配置三、维护操作1. 转换关系管理2.

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

Oracle数据库定时备份脚本方式(Linux)

《Oracle数据库定时备份脚本方式(Linux)》文章介绍Oracle数据库自动备份方案,包含主机备份传输与备机解压导入流程,强调需提前全量删除原库数据避免报错,并需配置无密传输、定时任务及验证脚本... 目录说明主机脚本备机上自动导库脚本整个自动备份oracle数据库的过程(建议全程用root用户)总结

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

一文解密Python进行监控进程的黑科技

《一文解密Python进行监控进程的黑科技》在计算机系统管理和应用性能优化中,监控进程的CPU、内存和IO使用率是非常重要的任务,下面我们就来讲讲如何Python写一个简单使用的监控进程的工具吧... 目录准备工作监控CPU使用率监控内存使用率监控IO使用率小工具代码整合在计算机系统管理和应用性能优化中,监

MySQL逻辑删除与唯一索引冲突解决方案

《MySQL逻辑删除与唯一索引冲突解决方案》本文探讨MySQL逻辑删除与唯一索引冲突问题,提出四种解决方案:复合索引+时间戳、修改唯一字段、历史表、业务层校验,推荐方案1和方案3,适用于不同场景,感兴... 目录问题背景问题复现解决方案解决方案1.复合唯一索引 + 时间戳删除字段解决方案2:删除后修改唯一字

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

浅谈mysql的not exists走不走索引

《浅谈mysql的notexists走不走索引》在MySQL中,​NOTEXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引,下面就来介绍一下mysql的notexists走不走索... 在mysql中,​NOT EXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引。以下