2010-03-08 8 views
11

Ich habe eine SQL-Anweisung, wo ich Daten von 1200 ep_codes durch Verwendung von IN Klausel erhalten möchten. Wenn ich mehr als 1000 ep_codes innerhalb IN-Klausel einschließe, sagt Oracle, dass ich das nicht tun darf. Um dies zu überwinden, habe ich versucht, den SQL-Code wie folgt zu ändern:Oracle SQL: Wie verwendet man mehr als 1000 Elemente innerhalb einer IN-Klausel

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

Der Code wurde erfolgreich ausgeführt, aber die Ergebnisse sind seltsam (Berechnungsergebnisse für alle Perioden abgerufen werden, nicht nur für die 200.912, die nicht das, was ich wollen). Ist es angebracht, das unter Verwendung OR zwischen IN Klauseln zu tun, oder sollte ich zwei separate Codes als eins mit 1000 und das andere mit 200 ep_codes ausführen?


Pascal Martins Lösung funktionierte perfekt. Danke an alle, die mit wertvollen Anregungen beigetragen haben.

Antwort

16

Nicht sicher, dass die Verwendung so vieler Werte in einem IN() ist so gut, eigentlich - vor allem für Auftritte.

Wenn Sie sagen "die Ergebnisse sind seltsam", ist dies vielleicht, weil ein Problem mit den Klammern? Was passiert, wenn Sie dies versuchen, statt dessen, was Sie vorgeschlagen:

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

Ist es die Ergebnisse machen weniger seltsam?

+0

Ich habe die Frage aktualisiert, um die Dinge klar über die seltsamen Ergebnisse zu machen. Jetzt probiere ich den Code wie Sie vorgeschlagen haben (mit zusätzlichen Klammern). Sobald die Ergebnisse abgerufen sind, werde ich es dir sagen. –

+0

Danke, es funktioniert jetzt OK. Wiederum sehe ich, dass zusätzliche Klammern entscheidend sind. –

+0

Gern geschehen :-) - ja, Klammern können hilfreich sein ;-) –

25

Der empfohlene Weg, um dies in Oracle zu behandeln, ist eine temporäre Tabelle zu erstellen, schreiben Sie die Werte in diese und dann zutreten. Die Verwendung von dynamisch erstellten IN-Klauseln bedeutet, dass der Abfrageoptimierer eine 'harte Analyse' jeder Abfrage durchführt.

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

Wir haben vor kurzem einen Code von "in" in die Verwendung einer temporären Nachschlagetabelle geändert. Bei einigen Abfragen stieg die Leistung dramatisch von einigen Minuten auf eine Sekunde. – Rene

+1

Aber ist dies eine gültige Implementierung für mehrere parallele Anfragen an den Server? Soweit ich verstehe, kann es mehrere offene Transaktionen auf Oracle-Server geben, die versucht haben, eine Tabelle zu erstellen: "Lookup" –

+0

@Ilya: Siehe http://stackoverflow.com/questions/8240810/when-will-data-in-oracle-session -temporary-table-get-deletedMit "on commit delete rows" sollten die Daten nur im Rahmen der Transaktion sichtbar sein. – shelley

1

Es scheint, als wäre es eine bessere Idee, sowohl für die Leistung als auch die Wartbarkeit, die Codes in eine separate Tabelle zu setzen.

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

kann man die 1200 ep_code Werte in eine temporäre Tabelle einfügen und dann INNER JOIN auf diese Tabelle stattdessen Zeilen filtern?

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

Ich bin mir nicht sicher. Ich verwende einige Ansichten, die die IT für mich bereitgestellt hat. –

6

Eigentlich kann man Sammlungen/Multimengen hier verwenden. Sie benötigen einen Nummerntabellentyp, um sie zu speichern.

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

Lesen Sie mehr über Multimengen here:

+0

Dies ist sehr elegant syntaktisch, aber die Leistung ist enttäuschend. Unter Verwendung dieser Syntax zum Auswählen eines einzelnen Primärschlüsselwerts wählt das CBO einen INDEX-FAST-FULL-SCAN. –

+0

Testen mit ein paar tausend IDs und eine moderate Größe Tabelle (40K Zeilen), ist es immer noch etwa 3x schneller als Beitritt zu einer temporären Tabelle (aufgrund der Hash-Join). Die Zeit zum Erstellen und Auffüllen der temporären Tabelle wird nicht berücksichtigt. –

Verwandte Themen