Это вопрос производительности, упрощенный для объединения двух индексов. Возьмите следующую настройку:
CREATE TABLE ZZ_BASE AS SELECT dbms_random.random AS ID, DBMS_RANDOM.STRING('U',10) AS STR FROM DUAL CONNECT BY LEVEL <=1000000;
CREATE INDEX ZZ_B_I ON ZZ_BASE(ID ASC);
CREATE TABLE ZZ_CHILD AS SELECT dbms_random.random AS ID, DBMS_RANDOM.STRING('U',10) AS STR FROM DUAL CONNECT BY LEVEL <=1000000;
CREATE INDEX ZZ_C_I ON ZZ_CHILD(ID ASC);
-- As @Flado pointed out, the following is required so index scanning can be done
ALTER TABLE ZZ_BASE MODIFY (ID CONSTRAINT NN_B NOT NULL);
ALTER TABLE ZZ_CHILD MODIFY (ID CONSTRAINT NN_C NOT NULL); -- given the join below not mandatory.
Теперь я хочу ВЕРНУТЬ ВНЕШНЮЮ СОЕДИНЕНИЕ этих двух таблиц и только вывести уже проиндексированное поле идентификатора.
SELECT ZZ_BASE.ID
FROM ZZ_BASE
LEFT OUTER JOIN ZZ_CHILD ON (ZZ_BASE.ID = ZZ_CHILD.ID);
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 9765K| | 4894 (2)| 00:00:30 |
|* 1 | HASH JOIN OUTER | | 1000K| 9765K| 16M| 4894 (2)| 00:00:30 |
| 2 | INDEX FAST FULL SCAN| ZZ_B_I | 1000K| 4882K| | 948 (3)| 00:00:06 |
| 3 | INDEX FAST FULL SCAN| ZZ_C_I | 1000K| 4882K| | 948 (3)| 00:00:06 |
----------------------------------------------------------------------------------------
Как вы видите, нет необходимости в доступе к таблице, только доступ к индексу. Но, по здравому смыслу, HASH-соединение не является самым оптимальным способом объединения этих двух индексов. Если эти две таблицы, где намного больше, нужно будет создать очень большую хэш-таблицу.
Более эффективным способом было бы СОРТИРОВАТЬ два индекса.
SELECT /*+ USE_MERGE(ZZ_BASE ZZ_CHILD) */ ZZ_BASE.ID
FROM ZZ_BASE
LEFT OUTER JOIN ZZ_CHILD ON (ZZ_BASE.ID = ZZ_CHILD.ID);
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 9765K| | 6931 (3)| 00:00:42 |
| 1 | MERGE JOIN OUTER | | 1000K| 9765K| | 6931 (3)| 00:00:42 |
| 2 | INDEX FULL SCAN | ZZ_B_I | 1000K| 4882K| | 2258 (2)| 00:00:14 |
|* 3 | SORT JOIN | | 1000K| 4882K| 22M| 4673 (4)| 00:00:29 |
| 4 | INDEX FAST FULL SCAN| ZZ_C_I | 1000K| 4882K| | 948 (3)| 00:00:06 |
-----------------------------------------------------------------------------------------
Но кажется, что второй индекс сортируется, даже если он уже есть ( "Если индекс существует, то база данных может избежать сортировки первого набора данных. Однако база данных всегда сортирует второй набор данных независимо от индексов" 1)
В принципе, я хочу, это запрос, который использует соединение SORT-MERGE и мгновенно запускает вывод записей, то есть:
- нет соединения HASH, потому что сначала нужно сделать хеш-таблицу (накладные расходы IO, если они хранятся на диске) и, таким образом, не выводится мгновенно.
- нет NESTED LOOP, который, хотя и выводит мгновенно, имеет логарифмическую (N) сложность в индексе pokes и большие служебные данные ввода-вывода при несекретных чтениях индекса в случае большого индекса.