Oracle - Оптимизация SQL-запросов - Запрос выполняется в течение длительного времени

avatar
jolly
1 июля 2021 в 17:30
87
3
0

У меня есть сценарий, в котором данные клиентов создаются в одной схеме и передаются в другую схему для бизнес-операций. В некоторых случаях данные не передаются, поэтому я использую приведенный ниже запрос для определения отсутствующих данных. Но он продолжает работать, не возвращая данные, поскольку в обеих таблицах более 5 миллионов записей. Как оптимизировать и получить результат?

SELECT CUSTID FROM SCHEMA1.CUSTOMER WHERE CUSTID NOT IN(SELECT ID FROM SCHEMA2.CUST_TBL);

После добавления еще одного фильтра ответ на запрос остается таким же.

SELECT CUSTID FROM SCHEMA1.CUSTOMER WHERE CUSTID NOT IN(SELECT ID FROM SCHEMA2.CUST_TBL WHERE CUST_TYPE=0);

CUSTID и ID являются индексированными, уникальными и ненулевыми столбцами. CUST_TYPE не равно null, но не индексировано. Также пробовал с /*+parallel(50)*/

Версия Oracle: 19c

Источник
William Robertson
1 июля 2021 в 17:46
0

В зависимости от вашей версии Oracle, not in (subquery) может быть проблемой, когда custid или id являются столбцами, допускающими значение NULL. Если это так, вы можете попробовать добавить where id is not null во внутренний запрос (при условии, что ни один столбец не нуждается в уточнении имени таблицы) или переписать его как not exists. Кроме того, parallel(50) является чрезмерным. Я бы начал с простого parallel и предоставил решение Oracle.

William Robertson
1 июля 2021 в 18:03
0

На самом деле, теперь, когда я проверяю (например, здесь), анти-соединение с нулевым значением было добавлено еще в 11g, поэтому, вероятно, столбец, допускающий значение NULL, не является проблемой в вашем случае. Если бы вы могли поделиться планом выполнения и вашей версией Oracle, это было бы полезно.

jolly
2 июля 2021 в 06:33
0

поля id и custid являются обязательными и индексируемыми полями. Использование версии Oracle 19c

jolly
2 июля 2021 в 06:49
0

передача еще одного фильтра cust_type во внутренний запрос, который также не является нулевым столбцом. ВЫБЕРИТЕ CUSTID ИЗ SCHEMA1.CUSTOMER A, ГДЕ CUSTID НЕ ВХОДИТ (ВЫБЕРИТЕ ID ИЗ SCHEMA2.CUST_TBL B и B.cust_type=0 );

William Robertson
2 июля 2021 в 13:29
1

Я думаю, что в обновленной версии отсутствует ключевое слово where. Но в любом случае план выполнения был бы полезен вместе с более подробными цифрами. Сколько строк возвращает запрос? Сколько строк возвращает измененный подзапрос?

jolly
8 июля 2021 в 10:28
0

да, это where. пересмотренный подзапрос возвращает около 3,5 млн записей и проверяет 5 млн записей. при использовании запроса bobC() для возврата результатов требуется около 380 секунд. select custid from SCHEMA1.CUSTOMER c1 left join SCHEMA2.CUST_TBL c2 on c1.custid = c2.id where c2.id is null and c2.CUST_TYPE=0;

William Robertson
8 июля 2021 в 19:12
1

Необходимо проверить 5 М строк, чтобы убедиться, что они не входят в набор из 3,5 М строк. Индексы тут не помогут и, скорее всего, сделают его медленнее. Если это то, что происходит, это должно быть ясно из плана выполнения. Вы пробовали метод MINUS Литтлфута?

jolly
15 июля 2021 в 06:35
0

Да, это помогает. Спасибо, Уильям

Ответы (3)

avatar
BobC
1 июля 2021 в 23:39
1

Минус требует сортировки, поэтому не очень эффективен. Лучшим подходом было бы внешнее соединение:

.
select custid
from SCHEMA1.CUSTOMER c1
left join SCHEMA2.CUST_TBL c2
on c1.custid = c2.id
where c2.id is null

Если у вас достаточно ресурсов (ЦП, ввод-вывод, память), вы можете использовать параллелизм для дальнейшего повышения производительности.

avatar
Atif
1 июля 2021 в 17:47
1

Вы пробовали не существовать.

SELECT CUSTID FROM SCHEMA1.CUSTOMER A WHERE NOT EXIST
(SELECT 1 FROM SCHEMA2.CUST_TBL B WHERE A.ID = B.ID );
avatar
Littlefoot
1 июля 2021 в 17:44
0

Как насчет оператора set minus?

select custid from schema1.customer
minus
select id from schema2.cust_tbl;
BobC
2 июля 2021 в 15:49
0

Минус требует сортировки.