Similar to SQLServer where I can do the following
create index TimeSeriesPeriodSs1 on TimeSeriesPeriod (validationStatus, completionStatus)
where completionStatus= N'Complete'
and validationStatus= N'Pending'
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)
);
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.
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)
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';
来源:https://stackoverflow.com/questions/5939776/does-oracle-have-a-filtered-index-concept