Oracle 11 Index仅用于部分数据

Fra*_*fka 2 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语句中获得一些子句?

Bra*_*vic 7

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

  • 您希望加速,SELECT .. WHERE C_D IS NULL但您希望加速搜索非NULL C_D的任何查询.
  • 您还需要确保索引中没有"不必要的"非NULL值,以节省空间.

如果这种理解是正确的,那么你需要的是一个功能索引.I'e.字段上函数的索引,而不是字段本身...

CREATE INDEX T_IE1 ON T (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) COMPRESS
Run Code Online (Sandbox Code Playgroud)

...然后你会查询...

SELECT * FROM T WHERE (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1
Run Code Online (Sandbox Code Playgroud)

......相当于......

SELECT * FROM T WHERE C_D IS NULL
Run Code Online (Sandbox Code Playgroud)

...但由于它使用索引更快:

在此输入图像描述

这节省了空间,因为单列索引不存储NULL.此外,使用COMPRESS因为索引将只包含一个键,因此在索引结构中一遍又一遍地重复相同的键不需要浪费空间.

注意:在Oracle 11下,您还可以创建基于函数的虚拟列(基于上面的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)
Run Code Online (Sandbox Code Playgroud)

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

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

...相当于......

SELECT * FROM T WHERE C_I > 'some value' AND C_D IS NULL
Run Code Online (Sandbox Code Playgroud)

...但速度更快,因为它使用了索引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)
Run Code Online (Sandbox Code Playgroud)

这使用索引:

SELECT * FROM T WHERE C_I > 1 AND C_D IS NULL
Run Code Online (Sandbox Code Playgroud)

与之前的EDIT一样,这是您桌面上唯一需要的索引.