Натхненний @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).