最近在办公室里,听见这么一段对话:

Bob: Alice,我看了下你昨天告诉我的那个慢查询,我已经把你想要的那个索引给加上去。现在肯定OK了。

Alice:谢谢你,Bob。我马上确认一下…不对啊,还是很慢,看起来没起作用啊

Bob:还真是。看起来Oracle没有用上这个索引,你那个查询我加了/+INDEX(...)/索引提示也不行。真是不知道怎么回事了。

然后,问题仍然没有解决。Alice很头疼,因为她要加的特性没有按时发现,Bob也很发愁,因为他觉得Oracle居然没有正常工作。

这是个真事。

Bob忘了Oralce和NULL值的问题了

可怜的Bob忘了,Oralce是不会把NULL放到普通索引里的。你想一下这种情况:

CREATE TABLE person (

id NUMBER(38) NOT NULL PRIMARY KEY,

first_name VARCHAR2(50) NOT NULL,

last_name VARCHAR2(50) NOT NULL,

date_of_birth DATE NULL

);

CREATE INDEX i_person_dob ON person(date_of_birth);

现在Bob认为有了这个索引什么事都解决了,因为他用这个查询验证了下,这个索引确实是好使的:

SELECT *

FROM person

WHERE date_of_birth > DATE '1980-01-01’;

(当然了,你不应该使用select *)

这个查询的执行计划看起来很正常:

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

| Id | Operation | Name |

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

| 0 | SELECT STATEMENT | |

| 1 | TABLE ACCESS BY INDEX ROWID| PERSON |

|* 2 | INDEX RANGE SCAN | I_PERSON_DOB |

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

这是因为Bob的查询并不需要NULL作为IPERSONDOB索引的一部分。不幸的是,Alice的查询看起来大概是这样的:

SELECT 1

FROM dual

WHERE DATE '1980-01-01' NOT IN (

SELECT date_of_birth FROM person

);

实际上,Alice的查询是判断是不是有人是这天生日的。她的执行计划看起来会是这样的:

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

| Id | Operation | Name |

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

| 0 | SELECT STATEMENT | |

|* 1 | FILTER | |

| 2 | FAST DUAL | |

|* 3 | TABLE ACCESS FULL| PERSON |

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

可以看到,她的查询进行了一个TABLE ACCESS FULL操作,索引被忽略了。为什么呢?很简单:

Oracle不会把NULL值放到索引里。

NOT IN(a, b, NULL, c, d)的结果是NULL。

不管你的这个日期’1980-01-01’在没在索引里,我们都得查看整个表来确认dateofbirth列中是否饮食一个NULL值。因为如果存在NULL值的话,Alice查询中这个NOT IN谓词的结果不是TRUE或FALSE,而是NULL。

Alice可以用NOT EXISTS来解决这个问题

这个问题其实Alice自己就可以很容易搞定,她只需要把NOT IN换成NOT EXISTS就好了,这个谓词能够绕过SQL的特殊的三值逻辑。

SELECT 1

FROM dual

WHERE NOT EXISTS (

SELECT 1

FROM person

WHERE date_of_birth = DATE '1980-01-01'

);

现在新的查询语句的确能够得到一个最优的执行计划:

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

| Id | Operation | Name |

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

| 0 | SELECT STATEMENT | |

|* 1 | FILTER | |

| 2 | FAST DUAL | |

|* 3 | INDEX RANGE SCAN| I_PERSON_DOB |

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

但问题仍然存在,因为该来的迟早还是会来的。Alice必须在写每条查询说一句的时候都时刻谨记这次教训。

对于Bob只需把这列设置成NOT NULL就好了

最佳的解决方案,其实就是把这列设置成NOT NULL就好了:

ALTER TABLE person

MODIFY date_of_birth DATE NOT NULL;

有了这个约束后,NOT IN查询就和NOT EXISTS查询是一样的了,Bob和Alice又可以一起快乐地玩耍了。

如何找出这些捣乱的列?

很简单。下面这个查询可以列出所有存在一个NULL值的索引列。

SELECT

i.table_name,

i.index_name,

LISTAGG(

LPAD(i.column_position, 2) || ': ' ||

RPAD(i.column_name , 30) || ' ' ||

DECODE(t.nullable, 'Y', '(NULL)', '(NOT NULL)'),

', '

) WITHIN GROUP (ORDER BY i.column_position)

AS "NULLABLE columns in indexes"

FROM user_ind_columns i

JOIN user_tab_cols t

ON (t.table_name, t.column_name) =

((i.table_name, i.column_name))

WHERE EXISTS (

SELECT 1

FROM user_tab_cols t

WHERE (t.table_name, t.column_name, t.nullable) =

((i.table_name, i.column_name, 'Y' ))

)

GROUP BY i.table_name, i.index_name

ORDER BY i.index_name ASC;

你现在再用Bob和Alice的schema来执行下,上述查询的结果是:

TABLE_NAME | INDEX_NAME | NULLABLE columns in indexes

-----------+--------------+----------------------------

PERSON | I_PERSON_DOB | 1: DATE_OF_BIRTH (NULL)

现在你可以在你自己的schema上运行下这条查询语句,仔细地看一下结果中的那些列有没有必要允许NULL值的出现。应该有半数的情况下是不该出现NULL值的。加上一个NOT NULL约束后,你的程序的性能可能会得到质的提升!

oracle索引可以加到in,为什么你加的索引不管用?相关推荐

  1. oracle将时间加一天,加小时,加分,加秒

    前言 oracle 时间类型可以直接相加,但加的是天,以天为单位,我们了解了这个,加一天,一小时,一分,一秒就都简单了. 加一天 select to_date('2019-08-15 22:03:10 ...

  2. mysql datetime month不走索引_like百分号加前面一定不走索引吗?一不小心就翻车,关于mysql索引那些容易错的点...

    like百分号加前面一定不走索引吗? 正常来讲,我们都知道在mysql的like查询中,百分号加在关键词后面是走索引的,比如 select * like "张三%",而百分号在前面 ...

  3. Oracle非重要文件恢复,redo、暂时文件、索引文件、password文件

    增量备份的应用在recovery阶段.不再restore阶段 了解数据库设置表: SQL>desc database_properties  Name                       ...

  4. Oracle设置sql执行时的并行度和强制走索引

    目录 1. 设置sql执行的并行度 2. 设置sql执行时强制走索引 1. 设置sql执行的并行度 在Oracle表中数据量比较大时,sql查询的速度会比较慢,这时候一种解决办法就是设置sql语句执行 ...

  5. mysql建立学号与课程编号的索引_数据库mysql 四约束 三范式 六索引

    mysql 四约束 三范式 六索引 1.MySQL 约束 1.约束的作用 分类 表列的primary key主键,unique唯一键,not null非空等修饰符常常被称作约束(constraint) ...

  6. 小程序一次性上传多个本地图片,上拉加载照片以及图片加载延迟解决之道

    一:小程序之一次性上传多个本地相片 最近由于项目需要所以学了下小程序,也做了一些东西,随后便有了以下的一些总结了,现在说说如何使用小程序一次性上传多个本地相片. 问题描述 最近做项目的时候要实现一个上 ...

  7. mysql中groupby会用到索引吗_开发人员不得不知的MySQL索引和查询优化

    本文主要总结了工作中一些常用的操作及不合理的操作,在对慢查询进行优化时收集的一些有用的资料和信息,本文适合有 MySQL 基础的开发人员. 索引相关 索引基数 基数是数据列所包含的不同值的数量,例如, ...

  8. 主键和索引哪个快_数据库两大神器【索引和锁】

    前言 只有光头才能变强 索引和锁在数据库中可以说是非常重要的知识点了,在面试中也会经常会被问到的. 本文力求简单讲清每个知识点,希望大家看完能有所收获 声明:如果没有说明具体的数据库和存储引擎,默认指 ...

  9. python列表索引超出范围 等于啥_python - IndexError:列表分配索引超出范围,Python

    我正在尝试实现功能.它的工作方式应该是这样的: 它需要两个列表. 标记一些索引,最好居中. 父母双方都切换标记索引. 其他索引按顺序转到其父元素. 如果该父元素中已经存在相同的元素,则它将映射并检查同 ...

  10. MySQL 为什么用索引,为什么是 B+树,怎么用索引

    MySQL 索引 A database index is a data structure that improves the speed of operations in a table. Inde ...

最新文章

  1. 阿里巴巴在应用性能测试场景设计和实现上的实践
  2. CMD、AMD、commonJs 规范的写法
  3. php round 取余,PHP round() 函数
  4. CCPC Training Class
  5. 收藏 | 佐治亚理工出品交互式线代教科书!
  6. 云原生2.0时代:企业更应了解一下容器安全
  7. 怎么找到python的文件_python – 如何找到文件所在的挂载点?
  8. python中if的输入格式_Python基础之输出格式和If判断
  9. linux 写地址 hex,你怎么理解Hex文件? (扩展地址记录)
  10. 【系列】关于直播,所有的技术细节都在这里了
  11. Jquery实现循环删除Reaper某一行
  12. oracle分析函数sum() over()
  13. eclipse中文版界面设置黑色_Eclipse设置黑色主题
  14. 红外与可见光图像融合(二)之思维导图
  15. 安全渗透测试 服务器 系统,一次完整的安全渗透测试
  16. CentOs解压缩命令
  17. Sdut PTA练习 2021级-JAVA01 Java入门
  18. echarts合并地图,把中国各个省份分成华北,东北,华东,华中,华南,西南,西北七个大区...
  19. 【U盘主控芯片的优缺点】
  20. 恋词21版(2022.12.10)

热门文章

  1. 配置Windows server 用户和组权限实验详解
  2. 2018杭州电子科技大学计算机研究生复试笔试编程题第三题
  3. SSRS 动态设置分组依据及行组个数
  4. 如何解决cellIndex在IE下兼容性问题
  5. Flash Builder 使用
  6. [转]程序员最容易犯的几个技术上的错误
  7. 微信浏览器发送ajax请求执行多次解决方法
  8. Redis的中并发问题的解决方案小结
  9. 【报告分享】2020年教育行业OMO模式转型现状研究报告.pdf(附下载链接)
  10. 【报告分享】新世代、新圈层:2020垂直圈层营销报告(附下载链接)