2011-05-09 65 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)