Antes de mais nada, veja se entendi a pergunta corretamente:
- Você deseja acelerar
SELECT .. WHERE C_D IS NULL
mas você não deseja acelerar qualquer uma das consultas que pesquisam um C_D não NULL. - Você também deseja garantir que nenhum valor "desnecessário" não NULL esteja no índice, para economizar espaço.
Se esse entendimento estiver correto, então o que você precisa é de um funcional índice. Eu. um índice em uma função em um campo, não um campo em si...
CREATE INDEX T_IE1 ON T (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) COMPRESS
...que você então consultaria como...
SELECT * FROM T WHERE (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1
...que é equivalente a...
SELECT * FROM T WHERE C_D IS NULL
...mas mais rápido, pois usa o índice:
Isso economiza espaço porque os índices de coluna única não armazenam NULLs. Além disso, use
COMPRESS
já que o índice sempre conterá apenas uma chave, portanto, não há necessidade de desperdiçar espaço repetindo a mesma chave várias vezes na estrutura do índice. NOTA:No Oracle 11, você também pode criar uma coluna virtual baseada em função (baseado no
CASE
expressão acima), indexe e consulte essa coluna diretamente, para salvar algumas digitações repetitivas. --- EDITAR ---
Se você também estiver interessado em consultar C_I junto com
C_D IS NULL
, você poderia... CREATE UNIQUE INDEX T_IE2 ON T (C_I, CASE WHEN C_D IS NULL THEN 1 ELSE NULL END)
... e consulte com (por exemplo) ...
SELECT * FROM T WHERE C_I > 'some value' AND (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1
...que é equivalente a...
SELECT * FROM T WHERE C_I > 'some value' AND C_D IS NULL
...mas mais rápido, pois usa o índice
T_IE2
. Este é de fato o único índice que você precisa em sua tabela (ele "cobre" a chave primária, então você não precisa mais de um índice separado apenas em C_I). O que também significa que um mesmo ROWIDs nunca é armazenado em mais de um índice, o que economiza espaço.
NOTA:
COMPRESS
não faz mais sentido para o índice T_IE2
. --- EDITAR 2 ---
Se você se preocupa mais com a simplicidade do que com o espaço, basta criar um índice composto em {C_I, C_D}. O Oracle armazena valores NULL no índice composto desde que haja pelo menos um valor não NULL na mesma tupla:
CREATE UNIQUE INDEX T_IE3 ON T (C_I, C_D)
Isso usa o índice:
SELECT * FROM T WHERE C_I > 1 AND C_D IS NULL
Como no EDIT anterior, este é o único índice que você precisa em sua tabela.