В против ИЛИ Oracle, который быстрее? - PullRequest
18 голосов
/ 29 июня 2011

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

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

Ответы [ 5 ]

27 голосов
/ 29 июня 2011

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

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

7 голосов
/ 29 июня 2011

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

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

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

2 голосов
/ 27 июля 2012

В любом случае 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

SELECT STATEMENT
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 ИЛИ«ID» = 35 ИЛИ «ID» = 36 ИЛИ «ИД» = 37 ИЛИ «ИД» = 38 ИЛИ «ИД» = 39 ИЛИ «ИД» = 40 ИЛИ «ИД» = 41 ИЛИ «ИД» = 42 ИЛИ «ИД»"= 43 ИЛИ" ID "= 44 ИЛИ" ID "= 45 ИЛИ" ИД "= 46 ИЛИ" ИД "= 47 ИЛИ" ИД "= 48 ИЛИ" ИД "= 49 ИЛИ" ИД "= 50 ИЛИ" ИД "=51 ИЛИ «ИД» = 52 ИЛИ «ИД» = 53 ИЛИ «ИД» = 54 ИЛИ «ИД» = 55 ИЛИ «ИД» = 56 ИЛИ «ИД» = 57 ИЛИ «ИД» = 58 ИЛИ «ИД» = 59 ИЛИ«ID» = 60 ИЛИ «ID» = 61 ИЛИ «ИД» = 62 ИЛИ «ИД» = 63 ИЛИ «ИД» = 64 ИЛИ «ИД» = 65 ИЛИ «ИД» = 66 ИЛИ «ИД» = 67 ИЛИ «ИД»"= 68 ИЛИ" ID "= 69 ИЛИ" ID "= 70 ИЛИ" ИД "= 71 ИЛИ" ИД "= 72 ИЛИ" ИД "= 73 ИЛИ" ИД "= 74 ИЛИ" ИД "= 75 ИЛИ" ИД "=76 ИЛИ «ID» = 77 ИЛИ «ИД» = 78 ИЛИ «ИД» = 79 ИЛИ «ИД» = 80 ИЛИ «ИД» = 81 ИЛИ «ИД» =82 ИЛИ «ID» = 83 ИЛИ «ИД» = 84 ИЛИ «ИД» = 85 ИЛИ «ИД» = 86 ИЛИ «ИД» = 87 ИЛИ «ИД» = 88 ИЛИ «ИД» = 89 ИЛИ «ИД» = 90 ИЛИ«ID» = 91 ИЛИ «ID» = 92 ИЛИ «ИД» = 93 ИЛИ «ИД» = 94 ИЛИ «ИД» = 95 ИЛИ «ИД» = 96 ИЛИ «ИД» = 97 ИЛИ «ИД» = 98 ИЛИ «ИД»"= 99 ИЛИ" ID "= 100)

2 голосов
/ 04 июля 2011

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

1 голос
/ 17 мая 2013

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...