Подтвердить что ты не робот

Имеет ли Oracle концепцию фильтрованного индекса?

Подобно SQLServer, где я могу сделать следующее

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

Ответ 1

Вы можете создать функциональный индекс в 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)
       );

Ответ 2

Вы можете использовать для этого индекс на основе функций, хотя это не очень приятно для этого сценария:

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. См. здесь для получения дополнительной информации и примеров. Или это, из быстрого Google.

Ответ 3

Здесь небольшой вариант ответа Джастина и Алекса, который может сэкономить дополнительное пространство индекса и сделает измененный запрос более читаемым ИМО:

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)

Ответ 4

Потенциальная альтернатива/улучшение индексов на основе функций заключается в использовании виртуальных столбцов.

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