database - Oracle 11 索引只针对部分数据

标签 database oracle indexing oracle11g

我正在使用一个名为 T 的表,其中有一列名为 C_I(索引)和 C_D(数据)。

现在,如果 C_D = null,我只想在索引中包含该行。

CREATE INDEX T_INDEX ON T(C_I) STORAGE(BUFFER_POOL KEEP);

如何将一些 WHERE C_D IS NULL 子句放入此 create 语句中?

最佳答案

首先让我确保我正确理解了问题:

  • 您想加快 SELECT .. WHERE C_D IS NULL 但您不想想加快任何搜索非 NULL 的查询C_D。
  • 您还想确保索引中没有“不必要的”非 NULL 值,以节省空间。

如果这种理解是正确的,那么您需要的是一个功能性 索引。 IE。字段上函数的索引,而不是字段本身...

CREATE INDEX T_IE1 ON T (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) COMPRESS

...然后您将查询为...

SELECT * FROM T WHERE (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1

...相当于...

SELECT * FROM T WHERE C_D IS NULL

...但速度更快,因为它使用了索引:

enter image description here

这样可以节省空间,因为单列索引不存储 NULL。此外,使用 COMPRESS,因为索引永远只包含一个键,因此无需浪费空间在索引结构中一遍又一遍地重复相同的键。

注意:在 Oracle 11 下,您还可以创建 function-based virtual column (基于上面的 CASE 表达式),然后直接对该列进行索引和查询,以节省一些重复输入。

--- 编辑 ---

如果您还对查询 C_I 以及 C_D IS NULL 感兴趣,您可以...

CREATE UNIQUE INDEX T_IE2 ON T (C_I, CASE WHEN C_D IS NULL THEN 1 ELSE NULL END)

...并用(例如)...查询它

SELECT * FROM T WHERE C_I > 'some value' AND (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1

...相当于...

SELECT * FROM T WHERE C_I > 'some value' AND C_D IS NULL

...但更快,因为它使用索引 T_IE2

这实际上是您在表上唯一需要的索引(它“覆盖”了主键,因此您不再需要仅在 C_I 上的单独索引)。这也意味着相同的 ROWID 永远不会存储在多个索引中,从而节省了空间。

注意:COMPRESS 对索引 T_IE2 不再有意义。

--- 编辑 2 ---

如果你更关心简单性而不是空间,你可以只在 {C_I, C_D} 上创建一个复合索引。只要同一元组中至少有一个非 NULL 值,Oracle 就会将 NULL 值存储在复合索引中:

CREATE UNIQUE INDEX T_IE3 ON T (C_I, C_D)

这使用索引:

SELECT * FROM T WHERE C_I > 1 AND C_D IS NULL

与之前的 EDIT 一样,这是您表中唯一需要的索引。

关于database - Oracle 11 索引只针对部分数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7696467/

相关文章:

sql - ORACLE SQL - 创建不相交的特化

python - cx_oracle中Connection.ping()的返回值是多少?

hadoop - Hbase、区域服务器、存储文件大小、索引

python - 如何删除 Pandas 数据框中的索引名称?

mysql select with in子句不使用索引

php - 在 php 中,我可以在从 url 获取变量的同时循环更新数据库吗?

php - MySQL 数据库保存 0 个值

php - 单个 php 网站页面内的多个数据库

mysql - 一个数据库多个接口(interface)

Java日期长值插入后改变,选择查询