Oracle - столбец даты в индексе игнорируется - PullRequest
0 голосов
/ 21 января 2020

У нас есть несколько индексов, включая столбцы даты, которые в Плане объяснения не нужны,

Пример таблицы A со столбцами ID NUMBER и CREATE_DATE DATE,

Первичного ключа нет и иметь индекс A_I1 с обоими столбцами

CREATE TABLE A (ID NUMBER,CREATE_DATE DATE);
CREATE INDEX A_I1 ON A (ID, CREATE_DATE);

Когда я делаю План объяснения для выбора без столбца даты oracle все еще использует индекс, SQL

 SELECT * from A where ID = 1;

Объясните план:

INDEX RANGE SCAN | A_I1
Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("ID"=1)

Объяснить план при выборе только со столбцом даты oracle все еще использует индекс с FULL SCAN, SQL:

SELECT * from A where CREATE_DATE = sysdate;

Объяснить план:

INDEX FULL SCAN | ZZ_A_I1
Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("CREATE_DATE"=SYSDATE@!)
* 1 - filter("CREATE_DATE"=SYSDATE@!)

Почему столбец даты игнорируется?

Ответы [ 3 ]

1 голос
/ 21 января 2020

Из документации (выделение добавлено):

Составные индексы могут ускорить получение данных для операторов SELECT, в которых предложение WHERE ссылается на все или ведущая часть столбцов в составном индексе. Следовательно, порядок столбцов, используемых в определении, важен. В общем, наиболее часто используемые столбцы go first.

Если вы фильтруете только по лидирующим столбцам - id в вашем случае - тогда индекс по-прежнему используется для идентификации этих строк, и другие столбцы игнорируются. Если вы фильтруете по всем столбцам в индексе, то будет идентифицировано меньшее количество записей индекса; поэтому, когда вы знаете оба значения столбца, которые ищете, это все равно будет более эффективным.

Если вы будете когда-либо только фильтровать в id и всегда будете получать все даты, тогда не будет много Можно сделать его составным индексом, но если вы иногда / обычно будете фильтровать по обоим столбцам, тогда составной лучше, чем индексировать только по id (или иметь отдельные индексы для id и create_date).

Если вы фильтруете только по create_date Oracle, иногда можете выбрать «пропустить сканирование», если оно считает это целесообразным:

В некоторых случаях, например, когда передний столбец имеет очень с низкой кардинальностью, база данных может использовать сканирование с пропуском этого индекса (см. « сканирование с пропуском индекса »).

Даже если она не может этого сделать, она может выполнить полное сканирование индекса, если оно считает, что это более эффективно, чем полное сканирование таблицы - опять-таки, отчасти это зависит от количества элементов, а также от того, ссылаетесь ли вы на неиндексированные столбцы.

В вашем примере это кажется вероятным который id уникален, и поэтому каждый id может иметь только один create_date, что может повлиять на ваш дизайн индекса - но в настоящий момент вы все еще можете использовать сканирование с пропуском по этому индексу, чтобы найти строки, созданные в определенную дату range.

Если у вашей реальной таблицы действительно есть другие столбцы, тогда, если вы хотите только получить значения идентификатора и даты, наличие даты в индексе также означает, что может вообще не понадобиться просматривать таблицу - это можно получить все, что ему нужно, из индекса, с меньшим количеством попаданий в кэш / диск. (Опять же, все это зависит от того, что оптимизатор решит, что это наиболее эффективный путь доступа для указанных c запросов, данных и статистики ...)

1 голос
/ 21 января 2020

Если столбец ID является первичным ключом, вы никогда не увидите INDEX SKIP SCAN в индексе с ID в качестве ведущего столбца.

Почему?

Oracle пришлось бы пропустить каждую строку в индексе, чтобы попасть в столбец DATE, что фактически означает, что вы получите доступ к каждой строке таблицы. Oracle знает, что это гораздо лучше сделать с TABLE ACCESS FULL.

Аналогично верно для столбца с большим количеством различных значений .

Индекс пропускает сканирование светится в том случае, если в ведущем столбце индекса только несколько значений - в приведенном ниже примере GROUP_ID имеет только три значения. Oracle решает использовать сканирование с пропуском, потому что это только в три раза дороже, чем доступ к индексу с использованием построения индекса по столбцу DATE - намного лучше, чем ПОЛНЫЙ СКАН для большой таблицы

Пример

create table B as
select mod(rownum,3) group_id, date'1990-01-01'+rownum CREATE_DATE 
from dual connect by level <= 1000000;

CREATE INDEX B_I1 ON B (ID, CREATE_DATE);

select * from B where CREATE_DATE = DATE'1991-01-01';

Plan hash value: 1197563700

-------------------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |    11 |     5   (0)| 00:00:01 |
|*  1 |  INDEX SKIP SCAN | B_I1 |     1 |    11 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------
...
Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("CREATE_DATE"=TO_DATE(' 1991-01-01 00:00:00', 
              'syyyy-mm-dd hh24:mi:ss'))
       filter("CREATE_DATE"=TO_DATE(' 1991-01-01 00:00:00', 
              'syyyy-mm-dd hh24:mi:ss'))
0 голосов
/ 21 января 2020

Oracle может искать данные в индексе, даже когда не все столбцы являются частью запроса.

Вот почему вы видите RANGE SCAN - база данных готова для просмотра диапазона записей индекса, которые имеют ID = 1 и включают в себя то, что находится в CREATE_DATE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...