2009-12-08 4 views
82

Possible en double:
T-SQL WHERE col IN (…)Taille maximale pour une requête SQL Server? Clause IN? Y at-il une meilleure approche

Quelle est la taille maximale pour une requête SQL Server? (Nombre de caractères)

Taille maximale pour une clause IN? Je pense avoir vu quelque chose à propos d'Oracle ayant une limite de 1000 objets, mais vous pourriez contourner cela avec ANDing 2 INs ensemble. Problème similaire dans SQL Server?

MISE À JOUR Alors, quelle serait la meilleure approche si je dois prendre dire 1000 GUIDs d'un autre système (non Relational Database) et faire un « join dans le code » contre le SQL Server? Est-il de soumettre la liste de 1000 GUIDs à ​​une clause IN? Ou est-il une autre technique qui fonctionne de manière plus efficace?

Je ne l'ai pas testé cela, mais je me demande si je pouvais présenter les GUIDs comme doc XML. Par exemple

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

et puis faire une sorte de XQuery JOIN contre le Doc et la Table. Moins efficace que 1000 article IN clause?

+1

semble être un double de: http: // stackoverflow. com/questions/1069415/t-sql-where-col-in – Yishai

+0

Laissez-moi ajouter à la question pour le rendre plus unique. voir mise à jour – BuddyJoe

+1

ressource que j'ai trouvé discutant de quelques idées - http://www.sommarskog.se/arrays-in-sql-2005.html#InsertMany – BuddyJoe

Répondre

64

Chaque lot SQL doit tenir dans la Batch Size Limit: 65 536 * Taille du paquet réseau.

À part cela, votre requête est limitée par les conditions d'exécution. La taille de la pile sera généralement dépassée car x IN (a, b, c) n'est rien d'autre que x = a OR x = b OU x = c qui crée un arbre d'expression similaire à x = a OR (x = b OR (x = c)), donc il devient très profond avec un grand nombre de OU. SQL 7 atteindrait un SO at about 10k values in the IN, mais les piles d'aujourd'hui sont beaucoup plus profondes (à cause de x64), donc ça peut aller assez loin.

Mise à jour

Vous avez déjà trouvé l'article de Erland sur le sujet des listes passant/tableaux à SQL Server. Avec SQL 2008, vous avez également Table Valued Parameters qui vous permet de transmettre un DataTable entier en tant que paramètre de type table unique et de s'y joindre.

XML et XPath est une autre solution viable:

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

"taille de pile": c'est l'erreur dont je ne me souviens pas – gbn

12

par lot, qui est 65536 * Network Packet Size 4k donc 256 Mo

Cependant, IN arrêter bien avant cela, mais ce n'est pas précis.

Vous vous retrouvez avec des erreurs de mémoire, mais je ne me souviens pas de l'erreur exacte. Un énorme IN sera inefficace de toute façon.

Edit: Remus m'a rappelé: l'erreur est de "taille de la pile"

34

Les Maximums SQL Server sont décrites http://msdn.microsoft.com/en-us/library/ms143432.aspx (ce qui est la version 2008)

Une requête SQL peut être un varchar (max) mais est montré comme limité à 65 536 * taille de paquet de réseau, mais même alors, ce qui est le plus susceptible de vous trébucher est les 2100 paramètres par requête. Si SQL choisit de paramétrer les valeurs littérales dans la clause in, je pense que vous atteindriez cette limite en premier, mais je ne l'ai pas testé. Editer: Testez-le, même sous paramétrage forcé il a survécu - J'ai fait un test rapide et je l'ai fait exécuter avec 30k éléments dans la clause In. (SQL Server 2005)

A 100k points, il a fallu un certain temps, puis a chuté avec:

Msg 8623, niveau 16, état 1, ligne 1 Le processeur de requête a manqué de ressources internes et ne pouvait pas produire un plan de requête. C'est un événement rare et seulement attendu pour les requêtes ou les requêtes extrêmement complexes qui font référence à un très grand nombre de tables ou de partitions. Merci de simplifier la requête. Si vous pensez avoir reçu ce message par erreur, contactez le service clientèle pour plus d'informations.

Alors 30k est possible, mais juste parce que vous pouvez le faire - ne signifie pas que vous devriez :)

Edit: Suite à la question en raison additionnelle.50k travaillé, mais 60k abandonné, donc quelque part là sur mon banc d'essai BTW.

En ce qui concerne la façon de faire cette jointure des valeurs sans utiliser une clause large in, personnellement, je créer une table temporaire, insérer les valeurs dans cette table temporaire, l'indexer puis l'utiliser dans une jointure les meilleures opportunités pour optimiser les jointures. (. Génération de l'index sur la table temporaire va créer des statistiques pour elle, ce qui contribuera à l'optimisateur en règle générale, bien que 1000 GUIDs ne trouverez pas exactement stats trop utile)

+1

voir mise à jour. merci pour les tests +1 – BuddyJoe

+0

Malheureusement, ces questions se produiraient régulièrement. Donc je ne pense pas que l'indexation de la table temporaire soit possible. Et pour les insertions rapides maximum la table principale sera indexée par un int 'addid' (ne sera pas indexée sur le GUID). Ce truc est plus délicat que je ne le pensais. – BuddyJoe

+1

Vous risquez une légère optimisation prématurée - vous devez obtenir quelques chiffres instrumentés en termes de plans de requêtes pour votre charge de travail, car il sera difficile à modéliser. Une fois que vous connaissez les chiffres des différentes approches, vous pouvez faire un choix, mais insérer 1k lignes dans une table temporaire SQL peut être fait exceptionnellement rapidement, cela dépend vraiment de comment/quoi le pilote. – Andrew

7

Pouvez-vous charger les GUIDs dans une table à gratter puis faites une

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

Si vous supposez que vous auriez ces requêtes toutes les secondes ou deux. Je me demande comment la table à gratter résiste. – BuddyJoe

+2

Nous utilisons extensivley cette technique dans notre application et il semble bien fonctionner. Tempdb doit être grand et nous faisons quelques réglages sur l'installation - je ne connais pas les détails de cela. Tempdb est occupé. – DaveE

Questions connexes