Zainspirowany @Paul „s odpowiedzi , zrobiłem kilka badań i stwierdził, że o ile prawdą jest, że przestrzeń stosu ogranicza liczbę powiązań,, i że przestrzeń stosu jest funkcją dostępną pamięć, a tym samym zmienia się następujące dwa punkty są również prawdziwe :
- istnieje sposób na wtłoczenie dodatkowych konkatenacji w jedno zdanie, ORAZ
- używając tej metody, aby wyjść poza początkowe ograniczenie miejsca na stosie, można znaleźć rzeczywisty limit logiczny (który nie wydaje się zmieniać)
Najpierw dostosowałem kod testowy Paula do łączenia ciągów:
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);
W tym teście najwyższe, jakie mogłem uzyskać, kiedy działałem na moim niezbyt świetnym laptopie (tylko 6 GB pamięci RAM), to:
- 3311 (zwraca 3312 znaków) przy użyciu SQL Server 2017 Express Edition LocalDB (14.0.3006)
- 3512 (zwraca 3513 znaków) przy użyciu SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)
przed pojawieniem się błędu 8631 .
Następnie próbowałem pogrupować konkatenacje za pomocą nawiasów, tak aby operacja konkatenowała wiele grup konkatenacji. Na przykład:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
Dzięki temu mogłem znacznie przekroczyć poprzednie limity zmiennych 3312 i 3513. Zaktualizowany kod to:
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);
Maksymalne wartości (dla mnie) mają teraz zostać użyte 42
dla pierwszej REPLICATE
, a więc przy użyciu 43 zmiennych na grupę, a następnie 762
dla drugiej REPLICATE
, a więc przy użyciu 762 grup po 43 zmienne każda. Grupa początkowa jest zakodowana na stałe za pomocą dwóch zmiennych.
Dane wyjściowe pokazują, że @S
zmienna zawiera 32 768 znaków . Jeśli zaktualizuję początkową grupę, aby była (@A+@A+@A)
zamiast (@A+@A)
, to pojawia się następujący błąd:
Msg 8632, poziom 17, stan 2, wiersz XXXXX
Błąd wewnętrzny: Osiągnięto limit usług wyrażania. Wyszukaj potencjalnie złożone wyrażenia w zapytaniu i spróbuj je uprościć.
Zauważ, że numer błędu jest inny niż wcześniej. Teraz jest: 8632 . I mam ten sam limit bez względu na to, czy korzystam z mojej instancji SQL Server 2012, czy SQL Server 2017.
To chyba nie przypadek, że górna granica tutaj - 32.768 - to maksymalna pojemność od SMALLINT
( Int16
w .NET) JEŻELI zaczynając od 0
(wartość maksymalna wynosi 32.767 ale tablice w wielu / większości języków programowania są oparte na 0).