Рассматривая две таблицы, объединенные таким образом:
select *
from table_1
left join table_2
on table_1.lnk_id = table_2.lnk_id
;
Существует индекс "lnk_id" для table_1 и table_2.Это возвращает 80 миллионов строк.
Я использую условное предложение where с переменными, установленными моим внешним интерфейсом (APEX):
: all: If = 1, должно возвращать все строки.
: требуемый_ид: объект, который я хочу вернуть.Может быть нулевым значением, и в этом случае я хочу вернуть только строки с нулевым значением.
Сначала я закодировал это:
select *
from table_1
left join table_2
on table_1.some_id = table_2.some_id
where (
case when :all = 1
then 1
when :desired_id is null and table_2.desired_id is null
then 1
when :desired_id = table_2.desired_id
then 1
else 0
end = 1
)
Учитывая: все = 0 и: требуемый_ид = некоторые не-Нулевое значение для выбора строк, которые желает пользователь, я испытываю ужасную производительность.
Я узнал, что мне нужно избегать выражения "case" в "where", поэтому он адаптирован к:
where (
:all = 1
or (:desired_id is null and table_2.desired_id is null)
or :desired_id = table_2.desired_id
)
НетВероятно, это так же медленно, как решение "дела".
Я понял это:
where (:desired_id = table_2.desired_id);
-> 0,047 с - Супер быстро
where (:desired_id = table_2.desired_id or 0 = 1);
--> 0,062 с - Сверхбыстрый
where (:desired_id = table_2.desired_id or :all = 1);
-> 235 с - Сверхскоростной
Так что я точно могу найти нужный объект в 80-рядных строкахвремя с конструкцией where (... = ... или ... = 1): оптимизатор должен принять неправильное решение, когда я использую: all.
Кто-нибудь сможет руководить?
Я бы предпочел избегать решения build-a-dynamic-query, если это возможно, так как оно делает его более сложным для реализации и управления, я считаю, и это действительно звучит как ...должен работать с простым SQL.
- Изменить, чтобы добавить планы -
Хороший план
select *
from table_2
left join table_1
on table_2.lnk_id = table_1.lnk_id
where (:desired_id = table_1.desired_id or 0 = 1);
Plan hash value: 1995399472
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 129 | 42183 | 45 (0)| 00:00:01 | | |
| 1 | NESTED LOOPS | | 129 | 42183 | 45 (0)| 00:00:01 | | |
| 2 | NESTED LOOPS | | 138 | 42183 | 45 (0)| 00:00:01 | | |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| TABLE_1 | 3 | 435 | 7 (0)| 00:00:01 | | |
|* 4 | INDEX RANGE SCAN | TABLE_1_I1 | 3 | | 3 (0)| 00:00:01 | | |
|* 5 | INDEX RANGE SCAN | TABLE_2_I2 | 46 | | 3 (0)| 00:00:01 | | |
| 6 | TABLE ACCESS BY GLOBAL INDEX ROWID | TABLE_2 | 40 | 7280 | 21 (0)| 00:00:01 | ROWID | ROWID |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("TABLE_1"."DESIRED_ID"=:DESIRED_ID)
5 - access("TABLE_2"."LNK_ID"="TABLE_1"."LNK_ID")
Неправильный план
explain plan for
select *
from table_2
left join table_1
on table_2.lnk_id = table_1.lnk_id
where (:desired_id = table_1.desired_id or :p3070100_all = 1);
Plan hash value: 94704160
----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 79M| 24G| | 1441K (1)| 00:00:57 | | |
|* 1 | FILTER | | | | | | | | |
|* 2 | HASH JOIN RIGHT OUTER| | 79M| 24G| 484M| 1441K (1)| 00:00:57 | | |
| 3 | TABLE ACCESS FULL | TABLE_1 | 3238K| 447M| | 19152 (1)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 79M| 13G| | 668K (1)| 00:00:27 | 1 |1048575|
| 5 | TABLE ACCESS FULL | TABLE_2 | 79M| 13G| | 668K (1)| 00:00:27 | 1 |1048575|
----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("TABLE_1"."DESIRED_ID"=:DESIRED_ID OR TO_NUMBER(:P3070100_ALL)=1)
2 - access("TABLE_2"."LNK_ID"="TABLE_1"."LNK_ID"(+))
Спасиботы, Дэвид