2011-06-29 54 views
17

我正在開發一個處理Oracle數據庫中的許多數據的應用程序。
在某些情況下,我必須根據給定的條件列表獲取許多對象,並且我使用SELECT ...FROM.. WHERE... IN...,但IN表達式只接受最大爲1,000個項目的列表。因此我使用OR表達式來代替,但正如我所觀察的 - 或許這個查詢(使用OR)比IN(具有相同的條件列表)慢。這樣對嗎?如果是這樣,如何提高查詢速度?Oracle與OR的比較哪個更快?

+0

列表是靜態還是派生自查詢? – Phil

+0

不,要查詢的值列表是從外部資源中檢索的。有沒有辦法解決這個問題,因爲我的列表太大,可能包含超過100000個項目 –

+1

因此,您正在創建一個包含類似IN(... 9997,9998,9999,1000,1001)的大量查詢字符串。 ..)?這本身會花費很多,傳輸和解析。不要介意sql注入的可能性。 –

回答

27

IN優於OR - OR是一個臭名昭着的糟糕的執行者,並且可能會導致其他問題需要在複雜查詢中使用括號。

INOR更好的選擇是加入包含您想要(或不想)的值的表格。這張用於比較的表格可以是派生的,臨時的,或者已經存在於您的模式中。

+1

不,我只在一張桌子上查詢。我的列表可能包含太多項目,因此我無法使用IN。我嘗試將列表拆分成較小的部分,並對一批子列表進行查詢,但後來我必須在內存中對數據進行排序,這非常緩慢。 –

+0

不是IN和OR相同嗎?也就是說,IN擴展到OR?這就是爲什麼NOT IN和NULL失敗 – gbn

+0

@gbn:從邏輯上說,是的。但是'IN'優於使用'OR' - 它不僅僅是語法糖。 –

7

在這種情況下,我會做這樣的:

  1. 創建一個列全局臨時表
  2. 從外部源與您的清單填寫此表(並迅速 - 另一個整個討論)
  3. 待辦事項你的查詢通過加入臨時表到另一個表(考慮動態採樣作爲臨時表將不會有很好的統計)

這意味着你可以離開排序到數據庫並寫一個簡單的查詢。

2

我會質疑整個方法。 SP的客戶端必須發送100000個ID。客戶從哪裏獲得這些ID?無論如何,發送如此大量的ID作爲proc的參數將會成本顯着。

2

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語句
TABLE ACCESS FULL( 「ID」= 1 OR 「ID」= 2 OR 「ID」= 3 OR 「ID」= 4或 「ID」= 5 OR「ID 「ID」= 7或「ID」= 8或「ID」= 9或「ID」= 10或「ID」= 21或 「ID」= 22或「ID」= 23或「ID」 = 24或「ID」= 25或「ID」= 26或「ID」= 27或 「ID」= 28或「ID」= 29或「ID」= 30或「ID」= 31或「ID」 32或「ID」= 33或 「ID」= 34或「ID」= 35或「ID」= 36或「ID」= 37或「ID」= 38或「ID」= 39或 「ID」 40或「ID」= 41或「ID」= 42或「ID」= 43或「ID」= 44或「ID」= 45或 「ID」= 46或「ID」= 47或「ID」= 48或「ID」= 49或「ID」= 50或「ID」= 51 O R「 」ID「= 52或」ID「= 53或」ID「= 54或」ID「= 55或」ID「= 56或」ID「= 57或 」ID「= 58或」ID「= 59 OR「ID」= 60或「ID」= 61或「ID」= 62或「ID」= 63或 「ID」= 64或「ID」= 65或「ID」= 66或「ID」 「ID」= 68或「ID」= 69或 「ID」= 70或「ID」= 71或「ID」= 72或「ID」= 73或「ID」= 74或「ID」= 75或 「ID」= 76或「ID」= 77或「ID」= 78或「ID」= 79或「ID」= 80或「ID」= 81或 「ID」= 82或「ID」 「ID」= 84或「ID」= 85或「ID」= 86或「ID」= 87或 「ID」= 88或「ID」= 89或「ID」= 90或「ID」 「= 92或」ID「= 93或 」ID「= 94或」ID「= 95或」ID「= 96或」ID「= 97或」ID「= 98或」ID「= 99或 」ID 「= 100)

+1

您創建的表是一個堆表 - 沒有主鍵/索引 –

+0

@OMGPonies Plus 1在您的答案中不報復jva報復。我知道很多人會這樣做。 – Mukus

1

如果您創建表的主鍵:

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

,並通過相同的選擇要與多個IN值,其次是通過哈希值獲取的執行計劃運行查詢,你得到的是:

SELECT STATEMENT 
INLIST ITERATOR 
INDEX     RANGE SCAN 

這似乎意味着,當你有一個IN列表,並使用此與PK列,甲骨文內部保存列表作爲「INLIST」,因爲它是更有效地處理此,而不是將其轉換爲ORs就像未索引表一樣。

我上面使用的是Oracle 10gR2。