2011-05-09 64 views
12

到SQLServer的相似,我可以做以下Oracle是否有過濾索引概念?

create index TimeSeriesPeriodSs1 on TimeSeriesPeriod (validationStatus, completionStatus) 
where completionStatus= N'Complete' 
and validationStatus= N'Pending' 
+0

你會不會只是創建一個正常的指標,並把在where子句中的選擇SQL?這樣,你的普通索引將爲不同的where子句表達命中相同的字段提供另一個select stmt。雖然不熟悉SQL Server篩選索引,但不清楚它的好處。 – tbone 2011-05-09 16:59:01

+1

@tbone - 大小可能是一個原因 – 2011-05-09 17:15:49

+2

@tbone:過濾索引的全部要點是爲了避免在只需要一小部分索引時在大表上維護索引的開銷。 – Gabe 2011-05-09 17:20:37

回答

13

您可以在Oracle中創建一個基於函數的索引,它利用NULL值不存儲在B樹索引的事實。喜歡的東西

CREATE INDEX TimeSeriesPeriodSs1 
    ON TimeSeriesPeriod( 
      (CASE WHEN completionStatus = 'Complete' AND validationStatus = 'Pending' 
       THEN validationStatus 
       ELSE NULL 
      END), 
      (CASE WHEN completionStatus = 'Complete' AND validationStatus = 'Pending' 
       THEN completionStatus 
       ELSE NULL 
      END) 
     ); 
+0

該死的,挫敗的agin ... – 2011-05-09 17:14:23

+1

alex poole答案是更好的,因爲它建議你使用用戶定義的函數,以避免必須寫在你的查詢的where子句中有同樣複雜的情況,以便oracle允許使用索引 – 2014-08-23 12:55:58

10

您可能能夠使用基於函數的索引對於這一點,但它不是爲這個場景非常愉快:

create index TimeSeriesPeriodSs1 on TimeSeriesPeriod (
    case when validationStatus= N'Pending' and completionStatus= N'Complete' then validationStatus else null end, 
    case when validationStatus= N'Pending' and completionStatus= N'Complete' then completionStatus else null end); 

你不得不使查詢的where子句完全匹配以使其使用索引。

select <fields> 
from TimeSeriesPeriod 
where case when validationStatus= N'Pending' and completionStatus= N'Complete' then validationStatus else null end = N'Pending' 
and case when validationStatus= N'Pending' and completionStatus= N'Complete' then completionStatus else null end = N'Complete'; 

這將是一個很大整潔,如果你可以定義(確定性)功能做case。有關更多信息和示例,請參閱here。或者從Google上快速獲得this

+1

+1來包含where子句以使用基於函數的索引。這與使用SQL Server的過濾索引與Oracle基於函數的索引相比有很大差異。 – 2011-05-09 18:51:42

6

這裏有賈斯汀和亞歷克斯的回答一個小的變體可能進一步節省索引空間,使修改後的查詢更具可讀性IMO:

CREATE INDEX TimeSeriesPeriodSs1 
    ON TimeSeriesPeriod( 
      (CASE WHEN completionStatus = 'Complete' AND validationStatus = 'Pending' 
       THEN 1 
       ELSE NULL 
      END); 

SELECT * FROM TimeSeriesPeriod 
    WHERE 1 = (CASE WHEN completionStatus = 'Complete' AND validationStatus = 'Pending' 
       THEN 1 
       ELSE NULL 
      END)