Lấy cảm hứng từ @ Paul 's câu trả lời , tôi đã làm một số nghiên cứu và phát hiện ra rằng trong khi nó là sự thật rằng ngăn xếp không gian không giới hạn số lượng concatenations, và rằng ngăn xếp không gian là một chức năng của bộ nhớ có sẵn và do đó thay đổi, hai điểm sau đây cũng là đúng sự thật :
- có một cách để nhồi nhét các phép nối bổ sung vào một câu lệnh AND
- sử dụng phương pháp này để vượt ra ngoài giới hạn không gian ngăn xếp ban đầu, có thể tìm thấy giới hạn logic thực tế (không có vẻ thay đổi)
Đầu tiên, tôi điều chỉnh mã kiểm tra của Paul để nối chuỗi:
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);
Với thử nghiệm này, mức cao nhất tôi có thể nhận được khi chạy trên máy tính xách tay không quá lớn của mình (chỉ có 6 GB RAM) là:
- 3311 (trả về 3312 tổng số ký tự) bằng SQL Server 2017 Express Edition LocalDB (14.0.3006)
- 3512 (trả về 3513 tổng số ký tự) bằng SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)
trước khi gặp lỗi 8631 .
Tiếp theo, tôi đã thử nhóm các phép nối bằng cách sử dụng dấu ngoặc đơn sao cho thao tác sẽ được nối nhiều nhóm nối. Ví dụ:
SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
Làm điều đó tôi đã có thể vượt xa các giới hạn trước đó của 3312 và 3513 biến. Mã cập nhật là:
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);
Các giá trị tối đa (đối với tôi) bây giờ là sử dụng 42
cho lần đầu tiên REPLICATE
, do đó sử dụng 43 biến cho mỗi nhóm, sau đó sử dụng 762
cho biến thứ hai REPLICATE
, do đó sử dụng 762 nhóm gồm 43 biến. Nhóm ban đầu được mã hóa cứng với hai biến.
Đầu ra bây giờ cho thấy có 32.768 ký tự trong @S
biến. Nếu tôi cập nhật nhóm ban đầu thành (@A+@A+@A)
thay vì chỉ (@A+@A)
, thì tôi gặp lỗi sau:
Msg 8632, Cấp 17, Trạng thái 2, Dòng XXXXX
Lỗi nội bộ: Đã đạt đến giới hạn dịch vụ biểu thức. Vui lòng tìm các biểu thức có khả năng phức tạp trong truy vấn của bạn và cố gắng đơn giản hóa chúng.
Lưu ý rằng số lỗi khác với trước đây. Bây giờ là: 8632 . VÀ, tôi có cùng giới hạn này cho dù tôi sử dụng phiên bản SQL Server 2012 hoặc phiên bản SQL Server 2017.
Có lẽ không phải ngẫu nhiên mà giới hạn trên ở đây - 32.768 - là dung lượng tối đa của SMALLINT
( Int16
trong .NET) NẾU bắt đầu từ 0
(giá trị tối đa là 32.767 nhưng mảng trong nhiều / hầu hết các ngôn ngữ lập trình đều dựa trên 0).