Вдохновленный @Paul «s ответ , я сделал некоторые исследования и обнаружил , что в то время как верно , что стек пространство действительно ограничивает количество сцеплений, и что стек пространство является функцией доступной памяти и , таким образом , изменяется, следующие два пункта также верно :
- есть способ втиснуть дополнительные объединения в одно утверждение, И
- Используя этот метод, чтобы выйти за пределы начального ограничения стека, можно найти фактический логический предел (который, кажется, не меняется)
Сначала я адаптировал тестовый код Пола для объединения строк:
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);
С этим тестом я смог получить максимум при работе на своем не очень хорошем ноутбуке (всего 6 ГБ ОЗУ):
- 3311 (возвращает всего 3312 символов) с использованием SQL Server 2017 Express Edition LocalDB (14.0.3006)
- 3512 (возвращает 3513 символов) с использованием SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)
до получения ошибки 8631 .
Затем я попытался сгруппировать конкатенации, используя круглые скобки, чтобы операция объединяла несколько групп конкатенаций. Например:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
Благодаря этому я смог выйти за пределы прежних границ переменных 3312 и 3513. Обновленный код:
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);
Максимальные значения (для меня) теперь должны использовать 42
для первого REPLICATE
, таким образом, используя 43 переменных на группу, а затем используя 762
для второго REPLICATE
, таким образом используя 762 группы по 43 переменных в каждой. Начальная группа жестко запрограммирована двумя переменными.
Вывод теперь показывает, что в @S
переменной 32 768 символов . Если я обновлю исходную группу, (@A+@A+@A)
а не просто (@A+@A)
, то получу следующую ошибку:
Сообщение 8632, уровень 17, состояние 2, строка XXXXX
Внутренняя ошибка: достигнут предел служб выражений. Пожалуйста, поищите потенциально сложные выражения в вашем запросе и постарайтесь упростить их.
Обратите внимание, что номер ошибки отличается от предыдущего. Сейчас: 8632 . И у меня есть такое же ограничение, использую ли я свой экземпляр SQL Server 2012 или экземпляр SQL Server 2017.
Это, вероятно , не случайно , что верхний предел здесь - 32768 - это максимальная емкость из SMALLINT
( Int16
в .NET) IF , начиная с 0
(максимальное значение 32767 , а массивы во многих / большинстве языков программирования от 0).