2009-12-08 2 views
82

Mögliche Duplizieren:
T-SQL WHERE col IN (…)Maximale Größe für eine SQL Server-Abfrage? IN-Klausel? Gibt es einen besseren Ansatz

Was ist die maximale Größe für eine SQL Server-Abfrage? (Anzahl der Zeichen)

Maximale Größe für eine IN-Klausel? Ich glaube, ich habe etwas über Oracle gesehen, das eine 1000-Item-Grenze hat, aber du könntest das mit ANDing von 2 INs umgehen. Ähnliches Problem in SQL Server?

UPDATE Also, was der beste Ansatz wäre, wenn ich nehmen muss sagen, 1000 GUIDs von einem anderen System (Non Relational Database) und machen Sie einen „im Code JOIN gegen den SQL Server? Ist es die Liste einreichen von 1000 GUIDs zu einer IN-Klausel? Oder gibt es eine andere Technik, die effizienten?

ich habe nicht das funktioniert getestet, aber ich frage mich, ob ich die GUIDs als XML-Dokument einreichen könnte. zum Beispiel

<guids> 
    <guid>809674df-1c22-46eb-bf9a-33dc78beb44a</guid> 
    <guid>257f537f-9c6b-4f14-a90c-ee613b4287f3</guid> 
</guids> 

und dann eine Art von XQuery JOIN gegen der Doc und der Tisch. Weniger effizient als 1000 Item IN-Klausel?

+1

Scheint ein Duplikat zu sein: http: // Stackoverflow. com/Fragen/1069415/t-sQL-wo-col-in – Yishai

+0

mich zu der Frage sie wollen, um es mehr einzigartig. siehe Update – BuddyJoe

+1

Ressource Ich fand einige Ideen diskutieren - http://www.sommarskog.se/arrays-in-sql-2005.html#InsertMany – BuddyJoe

Antwort

64

Jede SQL-Charge muss in die Batch Size Limit passen: 65.536 * Netzwerkpaketgröße.

Ansonsten ist Ihre Abfrage durch Laufzeitbedingungen eingeschränkt. Es wird normalerweise keine Stapelgröße mehr haben, da x IN (a, b, c) nichts anderes als x = a OR x = b OR x = c ist, wodurch ein Ausdruck erzeugt wird, der x = a OR ähnelt (x = b OR (x = c)), so wird es sehr tief mit einer großen Anzahl von OR. SQL 7 würde einen SO at about 10k values in the IN treffen, aber die Stacks von heute sind viel tiefer (wegen x64), also kann es ziemlich tief gehen.

aktualisieren

Sie schon gefunden Erland Artikel über das Thema Listen/Arrays zu SQL Server übergeben. Mit SQL 2008 haben Sie auch Table Valued Parameters, die es Ihnen ermöglichen, eine gesamte DataTable als einen einzelnen Tabellentypparameter zu übergeben und daran teilzunehmen.

XML und XPath ist eine andere praktikable Lösung:

SELECT ... 
FROM Table 
JOIN (
    SELECT x.value(N'.',N'uniqueidentifier') as guid 
    FROM @values.nodes(N'/guids/guid') t(x)) as guids 
ON Table.guid = guids.guid; 
+0

"Stapelgröße": das ist der Fehler, an den ich mich nicht erinnern konnte – gbn

12

Per Batch, 65536 * Network Packet Size die jedoch 4k so 256 MB

ist, wird sie IN Weg zu stoppen, bevor das, aber es ist nicht präzise.

Sie haben Speicherfehler, aber ich kann den genauen Fehler nicht abrufen. Ein großer IN wird sowieso ineffizient sein.

Edit: Remus erinnerte mich: der Fehler über "Stapelgröße"

34

Das SQL Server Maximum ist http://msdn.microsoft.com/en-us/library/ms143432.aspx offenbart (dies ist die Version 2008)

ein SQL-Abfrage kann eine varchar sein (max) Es wird jedoch gezeigt, dass es auf 65.536 * Netzwerkpaketgröße beschränkt ist, aber selbst dann stolpern die 2100 Parameter pro Abfrage am ehesten. Wenn SQL wählt, die Literalwerte in der In-Klausel zu parametrisieren, würde ich denken, dass Sie dieses Limit zuerst erreichen würden, aber ich habe es nicht getestet.

Edit: Teste es, auch unter erzwungener Parametrisierung hat es überlebt - ich habe einen Schnelltest gemacht und habe es mit 30k Items innerhalb der In-Klausel ausgeführt. (SQL Server 2005)

Bei 100k Artikeln, dauerte es einige Zeit fiel dann mit:

Msg 8623, Ebene 16, Status 1, Zeile 1 Der Abfrageprozessor lief aus internen Ressourcen und konnte nicht einen Abfrageplan erstellen. Dies ist ein seltenes Ereignis und wird nur für extrem komplexe Abfragen oder Abfragen erwartet, die auf eine sehr große Anzahl von Tabellen oder Partitionen verweisen. Bitte vereinfachen Sie die Abfrage. Wenn Sie der Meinung sind, dass Sie diese Nachricht irrtümlich erhalten haben, wenden Sie sich an den Kundendienst, um weitere Informationen zu erhalten.

So 30k ist möglich, aber nur, weil Sie es tun können - bedeutet nicht, Sie

bearbeiten :) sollte: Fortsetzung durch zusätzliche Frage.

50k funktionierte, aber 60k fiel aus, so irgendwo da auf meinem Prüfstand btw.

In Bezug auf wie die Join der Werte ohne eine große in-Klausel zu tun, würde ich persönlich eine temporäre Tabelle erstellen, die Werte in diese temporäre Tabelle einfügen, indizieren und dann in einem Join verwenden, geben Sie es die besten Möglichkeiten, die Joins zu optimieren. (Das Generieren des Indexes für die temporäre Tabelle erzeugt Statistiken, die den Optimierer als allgemeine Regel unterstützen, obwohl 1000 GUIDs die Statistiken nicht genau finden.

+1

siehe Update. Danke für die Prüfung +1 – BuddyJoe

+0

Leider würden diese Anfragen regelmäßig passieren. Ich denke also nicht, dass die Indizierung der Temp-Tabelle möglich ist. Und für max schnelle Einfügungen wird die Haupttabelle durch ein int 'addid' indiziert (wird nicht auf der GUID indiziert). Dieses Zeug ist kniffliger als ich dachte. – BuddyJoe

+1

Sie riskieren eine leichte vorzeitige Optimierung - Sie müssen sich in Bezug auf die Abfragepläne für Ihre Arbeitslast ein paar schwer instrumentierte Zahlen zulegen, da es schwer zu modellieren ist. Sobald Sie die Zahlen der verschiedenen Ansätze kennen, können Sie eine Auswahl treffen, aber das Einfügen von 1k-Zeilen in eine SQL-Tempentabelle kann außerordentlich schnell erfolgen, es hängt wirklich davon ab, wie/was es antreibt. – Andrew

7

Können Sie die GUIDs in eine Scratch-Tabelle dann ein

... WHERE var IN SELECT guid FROM #scratchtable 
tun laden
+0

Wenn Sie davon ausgehen, dass Sie diese Abfragen jede Sekunde oder zwei haben. Ich frage mich, wie der Kratztisch halten würde. – BuddyJoe

+2

Wir verwenden diese Technik in unserer App und es scheint gut zu funktionieren. Tempdb muss groß sein und wir tun ein wenig an der Installation - ich kenne die Einzelheiten nicht. Tempdb wird beschäftigt. – DaveE