web-dev-qa-db-fra.com

Y a-t-il une limite pour les résultats IN dans SQL Server?

Y a-t-il une limite pour le contenu que le filtre IN peut gérer? Par exemple:

SELECT Name
FROM People
WHERE Job IN (All the values goes here)

Documents Microsoft pour DANS dit:

"L'inclusion explicite d'un très grand nombre de valeurs (plusieurs milliers de valeurs séparées par des virgules) dans les parenthèses, dans une clause IN peut consommer des ressources et renvoyer des erreurs 8623 ou 8632. Pour contourner ce problème, stockez les éléments dans la liste IN dans une table et utiliser une sous-requête SELECT dans une clause IN. "

mais existe-t-il un nombre exact ou approximatif de

plusieurs milliers de valeurs

5
Unnamed

Ça dépend. Sérieusement. C'est pourquoi les documents ne peuvent pas être précis sur l'endroit où vous remarquerez une dégradation dans votre environnement.

La solution consiste simplement à arrêter de faire cela (et à s'en inquiéter) et à utiliser un paramètre table .

Si vous avez les valeurs en C # de telle manière que vous pouvez créer une liste séparée par des virgules sous forme de chaîne à concaténer ensemble dans une requête, vous avez les valeurs en C # de telle sorte que vous puissiez les bourrer dans un DataTable ou autre structure (peut-être que c'est d'où ils viennent en premier lieu), et passez cette structure en tant que paramètre à la procédure stockée.

10
Aaron Bertrand

À strictement parler, vous êtes assuré que la requête échouera avec 65536 valeurs. Cela dit, je pense qu'il est assez sûr de considérer 32768 comme une limite supérieure dans la pratique, mais ce n'est pas la moindre limite supérieure. La borne supérieure la moins élevée dépend de ce qui se passe dans la requête et d'autres facteurs locaux. Vous pouvez le voir avec un exemple simple. Mettez d'abord 100 000 lignes dans un tas:

DROP TABLE IF EXISTS dbo.Q228695;

CREATE TABLE dbo.Q228695 (ID BIGINT);

INSERT INTO dbo.Q228695 WITH (TABLOCK)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);

Supposons que je souhaite mettre 32768 valeurs dans la clause IN pour une requête de la forme suivante: SELECT COUNT(*) FROM dbo.Q228695 WHERE ID IN (); Ceci est facile à faire dans SQL Server 2017 avec STRING_AGG:

DECLARE @nou VARCHAR(MAX);

SELECT @nou = 'SELECT COUNT(*) FROM dbo.Q228695 WHERE ID IN (' + STRING_AGG(CAST(RN AS VARCHAR(MAX)), ',') + ')'
FROM
(
    SELECT TOP (32768) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
    FROM master..spt_values t1
    CROSS JOIN master..spt_values t2
) q
OPTION (MAXDOP 1);

EXEC (@nou);

J'obtiens l'erreur suivante:

Msg 8632, niveau 17, état 2, ligne 1

Erreur interne: une limite de services d'expression a été atteinte. Veuillez rechercher des expressions potentiellement complexes dans votre requête et essayez de les simplifier.

Si je supprime une valeur de la clause IN, la requête réussit après 24 secondes. Pour cette requête incroyablement simple, 32767 est le nombre maximal de valeurs qui permet toujours à la requête de s'exécuter. Notez que documentation Microsoft sur l'erreur 8632 dit ce qui suit:

Ce problème se produit car SQL Server limite le nombre d'identificateurs et de constantes pouvant être contenus dans une seule expression d'une requête. Cette limite est de 65 535.

32767 fonctionne et 32768 ne fonctionne pas. Je ne pense pas que ce soit une coïncidence que 65535/2 = 32767,5. Pour une raison quelconque, le comportement observé est que chaque constante de la clause IN compte comme deux vers la limite.

Je pense que ce n'est pas la bonne question à poser. Si je mets ces mêmes valeurs dans une table temporaire, la requête s'exécute en 0 secondes:

DROP TABLE IF EXISTS #t;

CREATE TABLE #t (ID BIGINT);

INSERT INTO #t WITH (TABLOCK)
SELECT TOP (32768) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);

SELECT COUNT(*)
FROM dbo.Q228695
WHERE ID IN (
    SELECT t.ID
    FROM #t t
);

Même si votre requête ne génère pas d'erreur, vous allez payer un lourd tribut aux performances une fois que vous avez mis trop de valeurs dans une clause IN.

5
Joe Obbish