2010-03-08 2 views
11

У меня есть оператор SQL, где я хотел бы получить данные 1200 ep_codes, используя статью IN. Когда я включаю более 1000 ep_codes внутри предложения IN, Oracle говорит, что мне не разрешено это делать. Чтобы преодолеть это, я попытался изменить код SQL следующим образом:Oracle SQL: Как использовать более 1000 элементов внутри предложения IN

SELECT period, ... 
FROM my_view 
WHERE period = '200912' 
     ... 
     AND ep_codes IN (...1000 ep_codes...) 
     OR ep_codes IN (...200 ep_codes...) 

код был выполнен успешно, но результаты странно (результаты расчета выбирается для всех периодов, а не только для 200912, который не то, что я хотеть). Уместно ли это сделать, используя OR между IN или я должен выполнить два отдельных кода как один с 1000, а другой с 200 ep_codes?


Решение Паскаля Мартина отлично работает. Спасибо всем, кто внес ценные предложения.

ответ

16

Не уверен, что использование большого количества значений в IN() является хорошим, на самом деле - особенно для выступлений.

Когда вы укажете "результаты поиска странные", может быть, это потому, что проблема с скобкой? Что делать, если вы попытаетесь это сделать, вместо того, что вы предложили:

SELECT ... 
FROM ... 
WHERE ... 
     AND (
      ep_codes IN (...1000 ep_codes...) 
      OR ep_codes IN (...200 ep_codes...) 
    ) 

ли это сделать результаты менее странно?

+0

Я обновил этот вопрос, чтобы сделать вещи ясно, о странных результатах. Теперь я пробую код, как вы предложили (с дополнительными скобками). Как только результаты будут получены, я скажу вам. –

+0

Спасибо, сейчас работает нормально. Еще раз я вижу, насколько важны дополнительные круглые скобки. –

+0

Добро пожаловать :-) - да, скобки могут быть полезны ;-) –

25

Рекомендуемый способ справиться с этим в Oracle - это создать временную таблицу, записать в нее значения и присоединиться к ней. Использование динамически созданных предложений IN означает, что оптимизатор запросов выполняет «жесткий анализ» каждого запроса.

create global temporary table LOOKUP 
(
    ID NUMBER 
) on commit delete rows; 

-- Do a batch insert from your application to populate this table 
insert into lookup(id) values (?) 

-- join to it 
select foo from bar where code in (select id from lookup) 
+2

Мы недавно сменили код с помощью «in» на использование временной таблицы поиска. Для некоторых запросов производительность резко увеличилась с нескольких минут до нескольких секунд. – Rene

+1

Но это допустимая реализация для нескольких параллельных запросов на сервер? Насколько я понимаю, на сервере Oracle может быть несколько открытых транзакций, пытаясь создать таблицу 'LOOKUP' –

+0

@Ilya: см. Http://stackoverflow.com/questions/8240810/when-will-data-in-oracle-session -temporary-таблица получить удаленный.С помощью «on commit delete rows» данные должны отображаться только в пределах транзакции. – shelley

1

Похоже, что было бы лучше, как для производительности, так и для удобства обслуживания, поместить коды в отдельную таблицу.

SELECT ... 
FROM ... 
WHERE ... 
    AND ep_code in (select code from ep_code_table) 
0

могли бы вы вставить 1200 ep_code значения во временную таблицу, а затем INNER JOIN к этой таблице для фильтрации строк вместо этого?

SELECT a.* 
FROM mytable a 
INNER JOIN tmp ON (tmp.ep_code = a.ep_code) 
WHERE ... 
+0

Я не уверен в этом. Я использую некоторые представления, которые предоставил мне ИТ. –

6

На самом деле вы можете использовать коллекции/мультимножества здесь. Для их хранения вам понадобится тип таблицы номеров.

CREATE TYPE NUMBER_TABLE AS TABLE OF NUMBER; 
... 
SELECT * 
FROM my_view 
WHERE period MEMBER OF NUMBER_TABLE(1,2,3...10000) 

Подробнее о мультимножествах here:

+0

Это очень элегантно синтаксически, но производительность разочаровывает. Используя этот синтаксис для выбора единственного значения первичного ключа, CBO выбирает INDEX FAST FULL SCAN. –

+0

Тестирование с помощью нескольких тысяч идентификаторов и таблицы с умеренным размером (40 тыс. Строк), она по-прежнему примерно в 3 раза быстрее, чем соединение на временной таблице (из-за хеш-соединения). Это не значит, что нужно создать и заполнить временную таблицу. –

Смежные вопросы