我正在使用一个名为 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
...但速度更快,因为它使用了索引:
这样可以节省空间,因为单列索引不存储 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/