Ограничение аргументов SQL в Oracle - PullRequest
7 голосов
/ 22 декабря 2009

Похоже, что в Oracle SQL существует ограничение в 1000 аргументов. Я столкнулся с этим при создании запросов, таких как ....

select * from orders where user_id IN(large list of ids over 1000)

Мой обходной путь - создать временную таблицу, сначала вставить в нее идентификаторы пользователей, а не выдавать запрос через JDBC с огромным списком параметров в IN.

Кто-нибудь знает более легкий обходной путь? Поскольку мы используем Hibernate, мне интересно, сможет ли он автоматически выполнить аналогичный обходной путь прозрачно.

Ответы [ 4 ]

4 голосов
/ 22 декабря 2009

Альтернативным подходом было бы передать массив в базу данных и использовать функцию TABLE() в предложении IN. Это, вероятно, будет работать лучше, чем временная таблица. Это, безусловно, будет более эффективным, чем выполнение нескольких запросов. Но вам нужно будет контролировать использование памяти PGA, если у вас есть большое количество сессий, выполняющих эту работу. Кроме того, я не уверен, насколько легко будет подключить это в Hibernate.

Примечание: TABLE() функции работают в движке SQL, поэтому им нужно, чтобы мы объявили тип SQL.

create or replace type tags_nt as table of varchar2(10);
/

В следующем примере массив заполняется парой тысяч случайных тегов. Затем он использует массив в предложении IN запроса.

declare
    search_tags tags_nt;
    n pls_integer;
begin

    select name 
    bulk collect into search_tags
    from ( select name 
           from temp_tags
           order by dbms_random.value )
    where rownum <= 2000;

    select count(*)
    into n
    from big_table
    where name in ( select * from table (search_tags) );

    dbms_output.put_line('tags match '||n||' rows!');
end;
/
3 голосов
/ 22 декабря 2009

Вы можете добавить дополнительные предикаты, чтобы разбить список на куски по 1000:

select * from orders where user_id IN (<first batch of 1000>)
OR user_id IN (<second batch of 1000>)
OR user_id IN ...
3 голосов
/ 22 декабря 2009

Пока временная таблица является глобальной временной таблицей (то есть видимой только для сеанса), это рекомендуемый способ действий (и я бы пошел по этому пути для чего-то большего, чем дюжина аргументов, не говоря уже о тысяч).

Интересно, где и как вы строите этот список из 1000 аргументов? Если это полупостоянная группировка (например, все сотрудники, базирующиеся в определенном месте), то эта группировка должна быть в базе данных, и объединение должно выполняться там. Базы данных спроектированы и созданы для быстрого объединения. Гораздо быстрее, чем вернуть группу идентификаторов обратно на средний уровень и затем отправить их обратно в базу данных.

select * from orders 
where user_id in 
(select user_id from users where location = :loc)
1 голос
/ 22 декабря 2009

комментарии относительно того, «если эти идентификаторы есть в вашей базе данных, вместо этого используйте соединения / корреляции», остаются в силе. Однако, если ваш список идентификаторов происходит из других источников, например, результат SOLR, вы можете обойти требование временной таблицы, выполнив несколько запросов, каждый из которых содержит не более 1000 идентификаторов, а затем объединяя результаты запроса в памяти. Если вы поместите первоначальный список идентификаторов в уникальную коллекцию, такую ​​как хэш-сет, вы можете одновременно выдавать 1000 идентификаторов.

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