Я пытаюсь использовать тип индекса и не работает. Может быть, вы можете помочь мне понять, что я делаю неправильно.
Это определение моей таблицы:
CREATE TABLE "TIR"."INT07NCMP"(
"INT07_CORRELATIVO" NUMBER(10) NOT NULL ENABLE,
"INT07_CENTRO" VARCHAR2(4 BYTE) NOT NULL ENABLE,
"INT07_CODCOMPONENTE" VARCHAR2(18 BYTE) NOT NULL ENABLE,
"INT07_ALMCOMPONENTE" VARCHAR2(4 BYTE) NOT NULL ENABLE,
"INT07_CANCOMPONENTE" NUMBER(13,3),
"INT07_UNICOMPONENTE" VARCHAR2(3 BYTE),
"INT07_CODPORTADOR" VARCHAR2(18 BYTE) NOT NULL ENABLE,
"INT07_ALMPORTADOR" VARCHAR2(4 BYTE) NOT NULL ENABLE,
"INT07_CANPORTADOR" NUMBER(13,3),
"INT07_UNIPORTADOR" VARCHAR2(3 BYTE),
"INT07_ALMDESTINO" VARCHAR2(4 BYTE) NOT NULL ENABLE,
"INT07_FECINICIO" VARCHAR2(10 BYTE) NOT NULL ENABLE,
"INT07_HORINICIO" VARCHAR2(8 BYTE) NOT NULL ENABLE,
"INT07_FECTERMINO" VARCHAR2(10 BYTE) NOT NULL ENABLE,
"INT07_HORTERMINO" VARCHAR2(8 BYTE) NOT NULL ENABLE,
"INT07_ESTPOCH" VARCHAR2(1 BYTE),
"INT07_TMPPOCH" TIMESTAMP (6),
"INT07_ESTSAP" VARCHAR2(1 BYTE),
"INT07_TMPSAP" TIMESTAMP (6),
"INT07_TIMESTAMP" TIMESTAMP (6) NOT NULL ENABLE,
CONSTRAINT "INT07NCMP_PK" PRIMARY KEY ("INT07_CORRELATIVO"),
CONSTRAINT "INT07NCMP_UK1" UNIQUE (
"INT07_CENTRO", "INT07_CODCOMPONENTE", "INT07_ALMCOMPONENTE", "INT07_CODPORTADOR", "INT07_ALMPORTADOR",
"INT07_FECINICIO", "INT07_HORINICIO", "INT07_FECTERMINO", "INT07_HORTERMINO"
)
);
и это индексы, которые я создал:
CREATE INDEX "TIR"."INT07NCMP_IDX1" ON "TIR"."INT07NCMP" ("INT07_CENTRO", "INT07_ESTPOCH");
CREATE INDEX "TIR"."INT07NCMP_IDX2" ON "TIR"."INT07NCMP" ("INT07_CENTRO", "INT07_ESTSAP");
CREATE INDEX "TIR"."INT07NCMP_IDX3" ON "TIR"."INT07NCMP" ("INT07_CENTRO", "INT07_CORRELATIVO", "INT07_FECINICIO", "INT07_HORINICIO", "INT07_FECTERMINO", "INT07_HORTERMINO");
Используя «Объяснить план», я хорошо работаю с индексами 1 и 2, но не с индексом 3. Например, я пытаюсь выполнить этот запрос:
SELECT * FROM INT07NCMP
WHERE INT07_CENTRO = '7100'
AND INT07_CORRELATIVO > 0
и это ответ:
Plan hash value: 2810525850
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9770 | 1450K| 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| INT07NCMP | 9770 | 1450K| 1 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | INT07NCMP_IDX1 | 39 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("INT07_CORRELATIVO">0)
2 - access("INT07_CENTRO"='7100')
Note
-----
- dynamic sampling used for this statement (level=2)
Итак, как вы можете видеть, использовался только IDX1, а я ожидал использовать IDX3, потому что я фильтрую с помощью "INT07_CENTRO", а затем "INT07_CORRELATIVO", точно так же, как порядок определения индекса. Если я попытаюсь поставить больше фильтров (все столбцы IDX3), это тоже не сработает.
Любой намек на это?
Спасибо
В какой доле строк INT07_CORRELATIVO > 0? Если их большинство, то индекс не очень избирательный, и оптимизатор может также выбрать меньший индекс или вообще не использовать его, так как INT07NCMP_IDX3 не поможет.


При условии, что у вас хорошая статистика. num_rows в user_tables и user_indexes.
Учитывая это, лучший подход в этих случаях — просто поверить, что db принимает правильное решение. он учитывает множество аспектов, например. статистика, физическая организация и т. д. Итак, сделайте индексы, как они должны быть, и создайте запрос в соответствии с правилами данных, а затем доверяйте БД.
В очень редких случаях может потребоваться форсировать запрос. Вы можете использовать подсказки. Но в этом случае, если это не имеет большого значения, в чем я сомневаюсь, просто добавление correlatoivo в конце первого индекса будет в порядке. Потому что экономия будет исходить не от сканирования диапазона на этом, а тому, что оракулу не нужно было переходить к таблице базы данных, чтобы получить это, и сканирования индекса было достаточно
И в этом случае можно с уверенностью предположить, что таблица нет имеет хорошую статистику, потому что - dynamic sampling used for this statement (level=2) подразумевает, что статистика на таблице вообще не собиралась. OP должен проверять, что задание автоматической статистики выполняется каждую ночь.
Вы собрали статистику по этой таблице? Например.
BEGIN DBMS_STATS.GATHER_TABLE_STATS('TIR', 'INT07NCMP'); END;, затем перепроверьте план запроса.