Inspirado por @ Paul 's resposta , eu fiz algumas pesquisas e descobrimos que, embora seja verdade que o espaço de pilha faz limite o número de encadeamentos, e que o espaço de pilha é uma função de memória disponível e, portanto, varia, os dois pontos seguintes também são verdadeiras :
- existe uma maneira de incluir concatenações adicionais em uma única declaração E
- Usando esse método para ir além da limitação inicial do espaço de pilha, pode ser encontrado um limite lógico real (que não parece variar)
Primeiro, adaptei o código de teste de Paul para concatenar seqüências de caracteres:
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);
Com este teste, o máximo que eu consegui ao executar no meu laptop não tão bom (apenas 6 GB de RAM) foi:
- 3311 (retorna 3312 caracteres totais) usando o SQL Server 2017 Express Edition LocalDB (14.0.3006)
- 3512 (retorna 3513 caracteres totais) usando o SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)
antes de obter o erro 8631 .
Em seguida, tentei agrupar as concatenações usando parênteses, para que a operação concatenasse vários grupos de concatenações. Por exemplo:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
Fazendo isso, fui capaz de ir muito além dos limites anteriores das variáveis 3312 e 3513. O código atualizado é:
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);
Os valores máximos (para mim) agora devem ser usados 42
para o primeiro REPLICATE
, usando 43 variáveis por grupo e, em seguida, usando 762
o segundo REPLICATE
, usando 762 grupos de 43 variáveis cada. O grupo inicial é codificado com duas variáveis.
A saída agora mostra que existem 32.768 caracteres na @S
variável. Se eu atualizar o grupo inicial em (@A+@A+@A)
vez de apenas (@A+@A)
, recebo o seguinte erro:
Msg 8632, Nível 17, Estado 2, Linha XXXXX
Erro interno: um limite de serviços de expressão foi atingido. Por favor, procure expressões potencialmente complexas em sua consulta e tente simplificá-las.
Observe que o número do erro é diferente do que antes. Agora é 8632 . E, eu tenho esse mesmo limite, usando minha instância do SQL Server 2012 ou a instância do SQL Server 2017.
Provavelmente não é coincidência que o limite superior aqui - 32.768 - seja a capacidade máxima de SMALLINT
( Int16
no .NET) IF iniciando em 0
(o valor máximo é 32.767, mas as matrizes na maioria das linguagens de programação são baseadas em 0).