90 votes

Taille maximale d'une requête SQL Server ? Clause IN ? Existe-t-il une meilleure approche

Duplicata possible :
T-SQL WHERE col IN ( )

Quelle est la taille maximale d'une requête SQL Server ? (nombre de caractères)

Taille maximale d'une clause IN ? Je crois avoir vu quelque chose à propos d'Oracle qui avait une limite de 1000 éléments, mais vous pourriez contourner cette limite en associant deux IN ensemble. Un problème similaire dans SQL Server ?

UPDATE Quelle serait donc la meilleure approche si je devais prendre 1000 GUIDs d'un autre système (base de données non relationnelle) et faire un 'JOIN in code' contre le serveur SQL ? Est-ce qu'il faut soumettre la liste des 1000 GUIDs à une clause IN ? Ou existe-t-il une autre technique qui fonctionne plus efficacement ?

Je ne l'ai pas testé mais je me demande si je ne pourrais pas soumettre les GUIDs sous forme de document XML. Par exemple

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

et ensuite faire une sorte de XQuery JOIN contre le Doc et le Tableau. Moins efficace que la clause 1000 item IN ?

74voto

Remus Rusanu Points 159382

Chaque lot SQL doit tenir dans le Limite de la taille des lots Taille des paquets réseau : 65 536 * Taille des paquets réseau.

En dehors de cela, votre requête est limitée par les conditions d'exécution. La taille de la pile sera généralement insuffisante car x IN (a,b,c) n'est rien d'autre que x=a OR x=b OR x=c, ce qui crée un arbre d'expression similaire à x=a OR (x=b OR (x=c)), et devient donc très profond avec un grand nombre d'OR. SQL 7 atteindrait un SO à des valeurs d'environ 10k dans l'IN Mais aujourd'hui, les piles sont beaucoup plus profondes (à cause de x64), donc cela peut aller assez loin.

Mise à jour

Vous avez déjà trouvé l'article d'Erland sur le sujet de passer des listes/rays à SQL Server. Avec SQL 2008 vous avez aussi Paramètres évalués par le tableau qui vous permettent de passer une DataTable entière comme paramètre unique de type de table et de la 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;

38voto

Andrew Points 14278

Les maximums du serveur SQL sont divulgués http://msdn.microsoft.com/en-us/library/ms143432.aspx (il s'agit de la version 2008)

Une requête SQL peut être un varchar(max), mais elle est limitée à 65 536 * taille du paquet réseau, mais même dans ce cas, ce qui risque le plus de vous faire trébucher, ce sont 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 atteindrez cette limite en premier, mais je ne l'ai pas testé.

Edit : Testé, même avec un paramétrage forcé, il a survécu - j'ai fait un test rapide et il s'est exécuté avec 30k éléments dans la clause In. (SQL Server 2005)

À 100 000 articles, cela a pris un certain temps puis a baissé avec :

Msg 8623, Niveau 16, État 1, Ligne 1 Le processeur de requêtes a manqué de ressources internes et n'a pas pu produire un plan de requête. Cet événement est rare et n'est attendu que pour des requêtes extrêmement complexes ou des requêtes qui font référence à un très grand nombre de tables ou de partitions. Veuillez simplifier la requête. Si vous pensez avoir reçu ce message par erreur, contactez les services d'assistance à la clientèle pour plus d'informations.

Donc 30k est possible, mais ce n'est pas parce que vous pouvez le faire que vous devez le faire :)

Edit : Continué en raison d'une question supplémentaire.

50k a fonctionné, mais 60k est tombé, donc quelque part entre les deux sur mon banc d'essai.

En ce qui concerne la façon de faire cette jointure des valeurs sans utiliser une clause in importante, personnellement, je créerais une table temporaire, j'insérerais les valeurs dans cette table temporaire, je l'indexerais et je l'utiliserais ensuite dans une jointure, ce qui lui donnerait les meilleures chances d'optimiser les jointures. (La génération de l'index sur la table temporaire créera des statistiques pour celle-ci, ce qui aidera l'optimiseur en règle générale, bien que 1000 GUIDs ne trouveront pas exactement les statistiques trop utiles).

12voto

gbn Points 197263

Par lot, 65536 * Taille des paquets réseau qui est 4k donc 256 MB

Cependant, l'IN s'arrêtera 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 de toute façon inefficace.

Edit : Remus m'a rappelé que l'erreur concerne la "taille de la pile".

7voto

DaveE Points 2779

Pouvez-vous charger les GUIDs dans une table scratch puis faire un

... WHERE var IN SELECT guid FROM #scratchtable

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X