IN vs OR Oracle, что быстрее?
Я разрабатываю приложение, которое обрабатывает многие данные в базе данных Oracle.
В каком-то случае мне нужно получить много объектов на основе заданного списка условий, и я использую SELECT ...FROM.. WHERE... IN...
, но выражение IN
просто принимает список размером не более 1000 элементов.
Итак, я использую выражение OR
вместо этого, но, как я вижу - возможно, этот запрос (используя OR
) медленнее, чем IN
(с тем же списком условий). Это правильно? И если да, то как повысить скорость запроса?
Ответы
Ответ 1
IN
предпочтительнее OR
- OR
является печально известным исполнителем и может вызвать другие проблемы, которые потребуются с использованием скобок в сложных запросах.
Лучший вариант, чем IN
или OR
, - это присоединиться к таблице, содержащей требуемые значения (или не хотите). Эта таблица для сравнения может быть получена, временная или уже существующая в вашей схеме.
Ответ 2
В этом случае я бы сделал следующее:
- Создать глобальную временную таблицу с одним столбцом
- Заполните эту таблицу своим списком из внешнего источника (и быстро - еще одно обсуждение)
- Сделайте свой запрос, присоединив временную таблицу к другой таблице (рассмотрите динамическую выборку, поскольку временная таблица не будет иметь хорошую статистику).
Это означает, что вы можете оставить сортировку в базе данных и написать простой запрос.
Ответ 3
Я бы поставил под сомнение весь подход. Клиент SP должен отправить 100000 идентификаторов. Откуда клиент получает эти идентификаторы? В любом случае отправка такого большого количества идентификаторов, как параметр proc, будет стоить значительно.
Ответ 4
Oracle внутренне конвертирует списки IN в списки ORs так или иначе, поэтому действительно не должно быть различий в производительности. Единственное различие заключается в том, что Oracle должен преобразовывать INs, но имеет более длинные строки для синтаксического анализа, если вы сами поставляете OR.
Вот как вы это тестируете.
CREATE TABLE my_test (id NUMBER);
SELECT 1
FROM my_test
WHERE id IN (1,2,3,4,5,6,7,8,9,10,
21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,
51,52,53,54,55,56,57,58,59,60,
61,62,63,64,65,66,67,68,69,70,
71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,
91,92,93,94,95,96,97,98,99,100
);
SELECT sql_text, hash_value
FROM v$sql
WHERE sql_text LIKE '%my_test%';
SELECT operation, options, filter_predicates
FROM v$sql_plan
WHERE hash_value = '1181594990'; -- hash_value from previous query
ВЫБОР ЗАЯВЛЕНИЯ
TABLE ACCESS FULL ( "ID" = 1 ИЛИ "ID" = 2 ИЛИ "ID" = 3 ИЛИ "ID" = 4 ИЛИ "ID" = 5 ИЛИ "ИД" = 6 ИЛИ "ИД" = 7 ИЛИ "ИД" = 8 ИЛИ "ИД" = 9 ИЛИ "ИД" = 10 ИЛИ "ИД" = 21 ИЛИ "ID" = 22 ИЛИ "ID" = 23 ИЛИ "ИД" = 24 ИЛИ "ИД" = 25 ИЛИ "ИД" = 26 ИЛИ "ИД" = 27 ИЛИ "ID" = 28 ИЛИ "ID" = 29 ИЛИ "ИД" = 30 ИЛИ "ИД" = 31 ИЛИ "ИД" = 32 ИЛИ "ИД" = 33 ИЛИ "ID" = 34 ИЛИ "ID" = 35 ИЛИ "ID" = 36 ИЛИ "ID" = 37 ИЛИ "ID" = 38 ИЛИ "ID" = 39 ИЛИ "ID" = 40 ИЛИ "ID" = 41 ИЛИ "ID" = 42 ИЛИ "ID" = 43 ИЛИ "ID" = 44 ИЛИ "ID" = 45 ИЛИ "ID" = 46 ИЛИ "ID" = 47 ИЛИ "ID" = 48 ИЛИ "ID" = 49 ИЛИ "ID" = 50 ИЛИ "ID" = 51 ИЛИ "ID" = 52 ИЛИ "ID" = 53 ИЛИ "ID" = 54 ИЛИ "ID" = 55 ИЛИ "ID" = 56 ИЛИ "ID" = 57 ИЛИ "ID" = 58 ИЛИ "ID" = 59 ИЛИ "ID" = 60 ИЛИ "ID" = 61 ИЛИ "ID" = 62 ИЛИ "ID" = 63 ИЛИ "ID" = 64 ИЛИ "ID" = 65 ИЛИ "ID" = 66 ИЛИ "ID" = 67 ИЛИ "ID" = 68 ИЛИ "ID" = 69 ИЛИ "ИД" = 70 ИЛИ "ИД" = 71 ИЛИ "ИД" = 72 ИЛИ "ИД" = 73 ИЛИ "ИД" = 74 ИЛИ "ИД" = 75 ИЛИ "ID" = 76 ИЛИ "ID" = 77 ИЛИ "ID" = 78 ИЛИ "ID" = 79 ИЛИ "ID" = 80 ИЛИ "ID" = 81 ИЛИ "ИД" = 82 ИЛИ "ИД" = 83 ИЛИ "ИД" = 84 ИЛИ "ИД" = 85 ИЛИ "ИД" = 86 ИЛИ "ИД" = 87 ИЛИ "ID" = 88 ИЛИ "ID" = 89 ИЛИ "ID" = 90 ИЛИ "ID" = 91 ИЛИ "ID" = 92 ИЛИ "ID" = 93 ИЛИ "ID" = 94 ИЛИ "ID" = 95 ИЛИ "ID" = 96 ИЛИ "ID" = 97 ИЛИ "ID" = 98 ИЛИ "ID" = 99 ИЛИ "ID" = 100)
Ответ 5
Если вы создаете таблицу с помощью первичного ключа:
CREATE TABLE my_test (id NUMBER,
CONSTRAINT PK PRIMARY KEY (id));
и пройти через те же самые SELECT, чтобы запустить запрос с несколькими значениями IN, а затем получить план выполнения с помощью хэш-значения, что вы получаете:
SELECT STATEMENT
INLIST ITERATOR
INDEX RANGE SCAN
Это означает, что если у вас есть список IN и используется с столбцом PK, Oracle сохраняет этот список внутренне как "INLIST", потому что более эффективно обрабатывать это, а не преобразовывать его в ORs, как в случай неиндексированной таблицы.
Я использовал Oracle 10gR2 выше.