Oracle是否有过滤索引概念?

时间:2011-05-09 16:30:36

标签: sql-server oracle filtered-index

与SQLServer类似,我可以执行以下操作

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

4 个答案:

答案 0 :(得分:14)

您可以在Oracle中创建基于函数的索引,利用NULL值未存储在b-tree索引中的事实。像

这样的东西
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)
       );

答案 1 :(得分:12)

您可能可以使用基于函数的索引,但这种情况不是很愉快:

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

答案 2 :(得分:6)

以下是Justin和Alex的答案的一个小变体,它可以节省更多索引空间并使修改后的查询更具可读性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)

答案 3 :(得分:1)

基于函数的索引的潜在替代/改进之处是利用虚拟列。

create table TimeSeriesPeriod (
  --...
  pendingValidation as (
    case when completionStatus = N'Complete' and validationStatus= N'Pending'
      then 1
    else null
  ) virtual
);
create index TimeSeriesPeriodSs1 on TimeSeriesPeriod (pendingValidation);

select * from TimeSeriesPeriod where pendingValidation = 1;

请注意,就像常规列一样,为虚拟列/基于函数的索引收集统计信息,因此它们的成本确实为非零。考虑尽可能将多个过滤器折叠到一个虚拟列中

create table TimeSeriesPeriod (
  --...
  incompleteValidationStatus as (
    case when completionStatus = N'Complete' and validationStatus != N'Complete'
      then validationStatus
    else null
  ) virtual
);
create index TimeSeriesPeriodSs1 on TimeSeriesPeriod (incompleteValidationStatus);

select * from TimeSeriesPeriod where incompleteValidationStatus = N'Pending';
select * from TimeSeriesPeriod where incompleteValidationStatus = N'Failed Validation';