Это ответ, почему утверждение продолжается вечно .
Если вы исследуете план выполнения, вы видите что-то вроде этого
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 500 | 45000 | 113 (0)| 00:00:02 |
| 1 | NESTED LOOPS OUTER| | 500 | 45000 | 113 (0)| 00:00:02 |
| 2 | TABLE ACCESS FULL| TAB_A | 100 | 4400 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| TAB_B | 5 | 230 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(INSTR("B"."B1"(+),"A"."A1"||'-'||"A"."A2")>0)
Таким образом, вы FULL SCAN
таблица TAB_A
и для каждой строки это вы FULL SCAN
таблица TAB_B
.
Технически, вы вычисляете декартово объединение двух таблиц (содержащих строки count (TAB_A) * count (TAB_B)) и затем фильтруете совпадения.
Кстати, никакая переформулировка предиката (с LIKE и т. Д.) Не изменит это поведение - это изменение только для предиката FILTER.
Единственное, что мне приходит на ум, вы можете сделать - если вам повезет, и TAB_B
содержит много строк без знака минус , чтобы отфильтровать их, так как эти строки по определению могут не сопоставьте и создайте временную таблицу меньшего размера, которая используется в объединении.
create table tab_b_tmp as
select * from tab_b
where b1 like '%-%' /* eliminate all rows that can't match */
;
Возможно, вы расширите эту логику, если найдете некоторые дополнительные шаблоны исключения, основанные на ваших данных.
Удачи!