Подтвердить что ты не робот

IN vs OR Oracle, что быстрее?

Я разрабатываю приложение, которое обрабатывает многие данные в базе данных Oracle.
В каком-то случае мне нужно получить много объектов на основе заданного списка условий, и я использую SELECT ...FROM.. WHERE... IN..., но выражение IN просто принимает список размером не более 1000 элементов.

Итак, я использую выражение OR вместо этого, но, как я вижу - возможно, этот запрос (используя OR) медленнее, чем IN (с тем же списком условий). Это правильно? И если да, то как повысить скорость запроса?

4b9b3361

Ответ 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 выше.