我正在使用一个名为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
子句?
答案 0 :(得分:7)
首先让我确保我正确理解这个问题:
SELECT .. WHERE C_D IS NULL
,但不想要加速搜索非NULL C_D的任何查询。如果这种理解是正确的,那么您需要的是功能性索引。 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
...但因为它使用了索引,所以更快:
这节省了空间,因为单列索引不存储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
查询计划: