В против ИЛИ Oracle, который быстрее?

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

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

5 ответов

Решение

IN предпочтительнее OR - OR является общеизвестно плохим исполнителем и может вызвать другие проблемы, которые потребуют использования скобок в сложных запросах.

Лучший вариант, чем любой IN или же OR, чтобы присоединиться к таблице, содержащей значения, которые вы хотите (или не хотите). Эта таблица для сравнения может быть производной, временной или уже существующей в вашей схеме.

В этом сценарии я бы сделал это:

  1. Создать глобальную временную таблицу с одним столбцом
  2. Заполните эту таблицу своим списком из внешнего источника (и быстро - еще одно целое обсуждение)
  3. Сделайте запрос, присоединив временную таблицу к другой таблице (рассмотрите динамическую выборку, поскольку временная таблица не будет иметь хорошую статистику)

Это означает, что вы можете оставить сортировку в базе данных и написать простой запрос.

В любом случае Oracle внутренне преобразует списки IN в списки OR, поэтому различий в производительности не должно быть. Единственное отличие состоит в том, что Oracle должен преобразовывать IN, но имеет более длинные строки для анализа, если вы сами предоставляете 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 ИЛИ "ID" = 6 ИЛИ "ID" = 7 ИЛИ "ID" = 8 ИЛИ "ID" = 9 ИЛИ "ID"=10 ИЛИ "ИД"=21 ИЛИ "ИД" = 22 ИЛИ "ИД" = 23 ИЛИ "ИД" = 24 ИЛИ "ИД" = 25 ИЛИ "ИД" = 26 ИЛИ "ID" = 27 ИЛИ "ID" = 28 ИЛИ "ИД" = 29 ИЛИ "ИД"=30 ИЛИ "ИД"=31 ИЛИ "ИД" = 32 ИЛИ "ИД" = 33 ИЛИ "ИД" = 34 ИЛИ "ИД" "= 35 ИЛИ" ID "= 36 ИЛИ" ID "= 37 ИЛИ" ИД "= 38 ИЛИ" ИД "= 39 ИЛИ" ИД "=40 ИЛИ" ИД "=41 ИЛИ" ИД "= 42 ИЛИ" ИД "= 43 ИЛИ "ID" = 44 ИЛИ "ID" = 45 ИЛИ "ИД" = 46 ИЛИ "ИД" = 47 ИЛИ "ИД" = 48 ИЛИ "ИД" = 49 ИЛИ "ИД"=50 ИЛИ "ИД"=51 ИЛИ "ID" = 52 ИЛИ "ID" = 53 ИЛИ "ИД" = 54 ИЛИ "ИД" = 55 ИЛИ "ИД" = 56 ИЛИ "ИД" = 57 ИЛИ "ИД" = 58 ИЛИ "ИД" = 59 ИЛИ "ИД" "=60 ИЛИ"ID"=61 ИЛИ" ID "= 62 ИЛИ" ИД "= 63 ИЛИ" ИД "= 64 ИЛИ" ИД "= 65 ИЛИ" ИД "= 66 ИЛИ" ИД "= 67 ИЛИ" ИД "= 68 ИЛИ "ID" = 69 ИЛИ "ID"=70 ИЛИ "ИД"=71 ИЛИ "ИД" = 72 ИЛИ "ИД" = 73 ИЛИ "ИД" = 74 ИЛИ "ИД" = 75 ИЛИ "ИД" = 76 ИЛИ "ID" = 77 ИЛИ "ID" = 78 ИЛИ "ИД" = 79 ИЛИ "ИД"=80 ИЛИ "ИД"=81 ИЛИ "ИД" = 82 ИЛИ "ИД" = 83 ИЛИ "ИД" = 84 ИЛИ "ИД" "= 85 ИЛИ" ID "= 86 ИЛИ" ID "= 87 ИЛИ" ИД "= 88 ИЛИ" ИД "= 89 ИЛИ" ИД "=90 ИЛИ" ИД "=91 ИЛИ" ИД "= 92 ИЛИ" ИД "= 93 ИЛИ "ID" = 94 ИЛИ "ID" = 95 ИЛИ "ИД" = 96 ИЛИ "ИД" = 97 ИЛИ "ИД" = 98 ИЛИ "ИД" = 99 ИЛИ "ИД"=100)

Я бы поставил под сомнение весь подход. Клиент ИП должен отправить 100000 идентификаторов. Откуда клиент получает эти идентификаторы? В любом случае отправка такого большого количества идентификаторов, как параметр proc, будет стоить значительно дороже.

Если вы создаете таблицу с первичным ключом:

CREATE TABLE my_test (id NUMBER,
CONSTRAINT PK PRIMARY KEY (id));

и выполните те же SELECT, чтобы выполнить запрос с несколькими значениями IN, а затем получить план выполнения с помощью значения хеш-функции, что вы получите:

SELECT STATEMENT
INLIST ITERATOR
INDEX                  RANGE SCAN

Похоже, это подразумевает, что когда у вас есть список IN и вы используете его со столбцом PK, Oracle хранит список внутри как "INLIST", потому что это более эффективно обрабатывать, чем преобразовывать его в OR, как в случае неиндексированная таблица.

Я использовал Oracle 10gR2 выше.

Другие вопросы по тегам