Oracle 11 Index仅用于部分数据

时间:2011-10-08 11:22:53

标签: database oracle indexing oracle11g

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

现在我想在C_D = null时只在索引中有行。

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

如何在此create语句中获得一些WHERE C_D IS NULL子句?

3 个答案:

答案 0 :(得分: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

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

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_D IS NULL一起查询C_I,您可以......

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

与之前的编辑一样,这是您桌面上唯一需要的索引。

答案 1 :(得分:3)

 CREATE INDEX T_INDEX ON T ( CASE WHEN CD IS NULL THEN C_I ELSE NULL END);

这是有效的,因为Oracle不会将CASE语句返回的空值放入索引中。

答案 2 :(得分:2)

让我“重新包装”我的original answer

像这样创建表:

CREATE TABLE T ...;
CREATE INDEX T_PK_IDX ON T (C_I, CASE WHEN C_D IS NULL THEN 1 ELSE NULL END);
ALTER TABLE T ADD CONSTRAINT T_PK PRIMARY KEY (C_I) USING INDEX T_PK_IDX;

并且像这样查询:

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

查询计划:

enter image description here