2009-12-21 33 views
7

Oracle SQL中似乎有1000個參數的限制。產生這樣的查詢....Oracle中的SQL參數限制

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

我的解決辦法是建立一個臨時表,插入用戶ID成第一,而不是發出通過JDBC的查詢都有一個參數列表巨頭時,我就遇到了這個在IN。

有誰知道更簡單的解決方法嗎?由於我們使用Hibernate,我想知道它是否能夠自動地透明地執行類似的解決方法。

+0

您是如何在首位生成大量id的列表的?他們是來自桌面還是查詢? (我以某種方式懷疑用戶界面生成了許多參數...) – YogoZuno 2009-12-21 23:36:08

+0

當ID列表來自其他來源(例如搜索引擎)時,通常會發生這種情況。即其在非整合後端之間進行關聯的方法。 – zzzeek 2009-12-21 23:41:27

+0

通常,ID來自用戶在UI上執行批量操作。 – benstpierre 2009-12-22 16:32:56

回答

4

另一種方法是傳遞一個數組到數據庫,並IN子句中使用TABLE()功能。這可能會比臨時表執行得更好。它肯定會比運行多個查詢更高效。但是如果你有大量會話在做這些事情,你需要監視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

只要臨時表是一個全局臨時表(即只對會話可見),這是推薦的做事方式(並且我會爲任何超過一打的參數走這條路線,更不用說了一千)。

我想知道你在哪裏/如何構建1000個參數的列表。如果這是一個半永久性分組(例如,所有員工都位於特定位置),那麼該分組應該在數據庫中,並且在那裏完成加入。數據庫的設計和構建非常迅速地進行連接。比將一堆id返回中間層然後將它們發送回數據庫要快得多。

select * from orders 
where user_id in 
(select user_id from users where location = :loc) 
1

有關「如果這些ID在您的數據庫中,請使用連接/關聯」的意見成立。但是,如果您的ID列表來自別處,例如SOLR結果,則可以通過發出多個查詢(每個查詢不超過1000個ID),然後在內存中合併查詢結果來解決臨時表需求。如果您將初始ID列表放入獨特集合(如哈希集合),則可以一次彈出1000個ID。

3

您可以添加額外的謂詞列表分割成塊1000:

select * from orders where user_id IN (<first batch of 1000>) 
OR user_id IN (<second batch of 1000>) 
OR user_id IN ...