Does Oracle have a filtered index concept?

后端 未结 4 1870
慢半拍i
慢半拍i 2020-12-10 13:29

Similar to SQLServer where I can do the following

create index TimeSeriesPeriodSs1 on TimeSeriesPeriod (validationStatus, completionStatus)
where completionS         


        
相关标签:
4条回答
  • 2020-12-10 13:41

    You can create a function-based index in Oracle that leverages the fact that NULL values aren't stored in b-tree indexes. Something like

    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 讨论(0)
  • 2020-12-10 13:48

    You might be able to use a function-based index for this, though it isn't very pleasant for this scenario:

    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);
    

    You'd have to make the query's where clause match exactly to make it use the index though.

    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';
    

    This would be a lot neater if you can define (deterministic) functions to do the case. See here for some further info and examples. Or this, from a quick Google.

    0 讨论(0)
  • 2020-12-10 13:48

    A potential alternative/improvement on function-based indexes is to make use of virtual columns.

    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;
    

    Note that statistics are collected for virtual columns/function-based indexes just like regular columns so they do have non-zero cost. Consider collapsing multiple filters into a single virtual column where possible

    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';
    
    0 讨论(0)
  • 2020-12-10 13:51

    Here's a small variant on Justin and Alex's answer that might save further index space and makes the modified query more readable 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)
    
    0 讨论(0)
提交回复
热议问题