Есть ли у Oracle концепция фильтрованного индекса? - PullRequest
12 голосов
/ 09 мая 2011

Аналогично SQLServer, где я могу сделать следующее

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

Ответы [ 4 ]

14 голосов
/ 09 мая 2011

В 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)
       );
12 голосов
/ 09 мая 2011

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

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.

6 голосов
/ 10 мая 2011

Вот небольшой вариант ответа Джастина и Алекса, который может сохранить дополнительное пространство индекса и сделать измененный запрос более читабельным 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)
1 голос
/ 23 февраля 2019

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

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';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...