У меня есть древовидная структура базы данных с id и parent_id, и я хочу создать представление, которое возвращает все старшие для данного дочернего идентификатора.Это всегда приводит к плану выполнения с полным сканированием таблицы.
Добавление подсказок или расчет статистики не помогли.Проблема воспроизводима даже при просмотре записей.Если я добавлю условие запуска непосредственно в оператор запуска, индекс будет использоваться и производительность будет хорошей.
-- Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
CREATE TABLE t AS (
SELECT 10 parent_id, 1 child_id FROM dual UNION ALL
SELECT 100 parent_id, 10 child_id FROM dual UNION ALL
SELECT NULL parent_id, 100 child_id FROM dual
);
CREATE INDEX child_idx ON t (child_id);
CREATE OR REPLACE VIEW parents_v AS
WITH recu(
start_id, child_id, parent_id
)
AS(
-- start
SELECT
child_id start_id, child_id, parent_id
FROM t
UNION ALL
SELECT
recu.child_id, pre.child_id, pre.parent_id
FROM recu, t pre
WHERE recu.parent_id = pre.child_id
)
SELECT * FROM recu;
Запрос на тестирование индекса:
SELECT * FROM t WHERE child_id = 1;
Объяснение плана:
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR);
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 26 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | CHILD_IDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Результат ОК, индекс CHILD_IDX используется
Запрос на проверку рекурсии:
SELECT * FROM parents_v WHERE start_id = 1;
Объяснить план:
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR);
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 7 (100)| |
|* 1 | VIEW | | 6 | 234 | 7 (15)| 00:00:01 |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| | | | | |
| 3 | TABLE ACCESS FULL | T | 3 | 78 | 2 (0)| 00:00:01 |
|* 4 | HASH JOIN | | 3 | 156 | 5 (20)| 00:00:01 |
| 5 | RECURSIVE WITH PUMP | | | | | |
| 6 | TABLE ACCESS FULL | T | 3 | 78 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Результат не ОК, индексCHILD_IDX используется , а не , всегда выполняется полное сканирование таблицы.