Ispirato da @ Paolo 's risposta , ho fatto qualche ricerca e ha scoperto che, se è vero che lo spazio di stack limita il numero di concatenazioni, e che lo spazio dello stack è una funzione della memoria disponibile e quindi varia, i seguenti due punti sono anche vero :
- c'è un modo per stipare concatenazioni aggiuntive in una singola istruzione, AND
- usando questo metodo per andare oltre la limitazione iniziale dello spazio dello stack, è possibile trovare un limite logico effettivo (che non sembra variare)
Innanzitutto, ho adattato il codice di test di Paul per concatenare le stringhe:
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);
Con questo test, il massimo che ho potuto ottenere quando sono in esecuzione sul mio laptop non così eccezionale (solo 6 GB di RAM) è stato:
- 3311 (restituisce 3312 caratteri totali) utilizzando SQL Server 2017 Express Edition LocalDB (14.0.3006)
- 3512 (restituisce 3513 caratteri totali) utilizzando SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)
prima di ottenere l'errore 8631 .
Successivamente, ho provato a raggruppare le concatenazioni utilizzando la parentesi in modo tale che l'operazione avrebbe concatenato più gruppi di concatenazioni. Per esempio:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
In questo modo sono stato in grado di andare ben oltre i limiti precedenti delle variabili 3312 e 3513. Il codice aggiornato è:
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);
I valori massimi (per me) ora sono da usare 42
per il primo REPLICATE
, usando quindi 43 variabili per gruppo, e quindi usando 762
per il secondo REPLICATE
, usando quindi 762 gruppi di 43 variabili ciascuno. Il gruppo iniziale è codificato con due variabili.
L'output ora mostra che ci sono 32.768 caratteri nella @S
variabile. Se aggiorno il gruppo iniziale in modo che sia (@A+@A+@A)
anziché solo (@A+@A)
, visualizzo il seguente errore:
Messaggio 8632, livello 17, stato 2, riga XXXXX
Errore interno: è stato raggiunto un limite di servizi di espressione. Cerca espressioni potenzialmente complesse nella tua query e prova a semplificarle.
Si noti che il numero di errore è diverso da prima. Ora è: 8632 . E, ho lo stesso limite se utilizzo la mia istanza di SQL Server 2012 o l'istanza di SQL Server 2017.
Probabilmente non è un caso che il limite superiore qui - 32.768 - sia la capacità massima di SMALLINT
( Int16
in .NET) IF a partire da 0
(il valore massimo è 32.767 ma gli array in molti / la maggior parte dei linguaggi di programmazione sono basati su 0).