Inspiré par @ Paul de réponse , je l' ai fait quelques recherches et a constaté que si il est vrai que l' espace de pile limite le nombre de concaténations, et que l' espace de pile est fonction de la mémoire disponible et varie donc, les deux points suivants sont également vrai :
- il existe un moyen de regrouper des concaténations supplémentaires en une seule instruction, ET
- en utilisant cette méthode pour aller au-delà de la limitation d'espace de pile initiale, une limite logique réelle (qui ne semble pas varier) peut être trouvée
Tout d'abord, j'ai adapté le code de test de Paul pour concaténer des chaînes:
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
DECLARE @S VARCHAR(MAX), @A VARCHAR(MAX) = ''a'';
SET @S = @A';
SET @SQL += REPLICATE(CONVERT(NVARCHAR(MAX), N' + @A'), 3312) + N';';
-- SET @S = @A + @A + @A...
SET @SQL += N'SELECT DATALENGTH(@S) AS [Chars In @S];';
EXECUTE (@SQL);
Avec ce test, le plus haut niveau que j'ai pu obtenir lors de l'exécution sur mon ordinateur portable pas si génial (seulement 6 Go de RAM) était:
- 3311 (renvoie 3312 caractères au total) à l'aide de SQL Server 2017 Express Edition LocalDB (14.0.3006)
- 3512 (renvoie 3513 caractères au total) à l'aide de SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)
avant d'obtenir l'erreur 8631 .
Ensuite, j'ai essayé de regrouper les concaténations en utilisant des parenthèses de sorte que l'opération concatène plusieurs groupes de concaténations. Par exemple:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
Ce faisant, j'ai pu aller bien au-delà des limites précédentes de 3312 et 3513 variables. Le code mis à jour est:
DECLARE @SQL VARCHAR(MAX), @Chunk VARCHAR(MAX);
SET @SQL = '
DECLARE @S VARCHAR(MAX), @A VARCHAR(MAX) = ''a'';
SET @S = (@A+@A)';
SET @Chunk = ' + (@A' + REPLICATE(CONVERT(VARCHAR(MAX), '+@A'), 42) + ')';
SET @SQL += REPLICATE(CONVERT(VARCHAR(MAX), @Chunk), 762) + ';';
SET @SQL += 'SELECT DATALENGTH(@S) AS [Chars In @S];';
-- PRINT @SQL; -- for debug
-- SET @S = (@A+@A) + (@A + @A...) + ...
EXECUTE (@SQL);
Les valeurs maximales (pour moi) sont maintenant à utiliser 42
pour la première REPLICATE
, utilisant ainsi 43 variables par groupe, puis à utiliser 762
pour la seconde REPLICATE
, utilisant ainsi 762 groupes de 43 variables chacun. Le groupe initial est codé en dur avec deux variables.
La sortie montre maintenant qu'il y a 32 768 caractères dans la @S
variable. Si je mets à jour le groupe initial au (@A+@A+@A)
lieu de simplement (@A+@A)
, j'obtiens l'erreur suivante:
Msg 8632, niveau 17, état 2, ligne XXXXX
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.
Notez que le numéro d'erreur est différent qu'auparavant. Il est maintenant: 8632 . ET, j'ai cette même limite si j'utilise mon instance SQL Server 2012 ou l'instance SQL Server 2017.
Ce n'est probablement pas une coïncidence si la limite supérieure ici - 32 768 - est la capacité maximale de SMALLINT
( Int16
dans .NET) IF à partir de 0
(la valeur maximale est 32 767 mais les tableaux dans de nombreux / la plupart des langages de programmation sont basés sur 0).