2011-09-30 39 views
76

Bất kỳ lúc nào trong quá khứ, nếu ai đó hỏi tôi kích thước tối đa cho varchar(max), tôi đã nói 2GB hoặc tra cứu chính xác figure (2^31- 1, hoặc 2147483647).Kích thước tối đa của biến varchar (max)

Tuy nhiên, trong một số thử nghiệm gần đây, tôi phát hiện ra rằng varchar(max) biến rõ ràng có thể vượt quá kích thước này:

create table T (
    Val1 varchar(max) not null 
) 
go 
declare @KMsg varchar(max) = REPLICATE('a',1024); 
declare @MMsg varchar(max) = REPLICATE(@KMsg,1024); 
declare @GMsg varchar(max) = REPLICATE(@MMsg,1024); 
declare @GGMMsg varchar(max) = @GMsg + @GMsg + @MMsg; 
select LEN(@GGMMsg) 
insert into T(Val1) select @GGMMsg 
select LEN(Val1) from T 

Kết quả:

(no column name) 
2148532224 
(1 row(s) affected) 
Msg 7119, Level 16, State 1, Line 6 
Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes. 
The statement has been terminated. 

(no column name) 
(0 row(s) affected) 

Vì vậy, cho rằng bây giờ tôi biết rằng một biến có thể vượt quá rào cản 2GB - có ai biết giới hạn thực tế cho biến số varchar(max) không?


(. Trên thử nghiệm hoàn tất vào SQL Server 2008 (không R2) Tôi muốn được quan tâm để biết liệu nó áp dụng cho các phiên bản khác)

+0

'declare @x varchar (max) = 'XX'; SELECT LEN (REPLICATE (@ x, 2147483647)) 'cung cấp cho '4294967294' cho tôi nhưng phải mất một thời gian dài để chạy - ngay cả sau khi' SELECT' đã quay trở lại để không chắc chắn những gì thêm thời gian được chi tiêu làm. –

Trả lời

62

Theo như tôi có thể nói không có giới hạn trên trong năm 2008.

Trong SQL Server 2005 các mã trong câu hỏi của bạn không thành công trên sự phân công vào biến @GGMMsg với

Cố để tăng LOB vượt quá kích thước tối đa cho phép là 2,147,483,647 byte.

mã dưới đây không thành công với

tái tạo: Chiều dài của kết quả vượt quá giới hạn độ dài (2GB) của mục tiêu loại lớn.

Tuy nhiên, dường như những giới hạn này đã được dỡ bỏ một cách lặng lẽ.Trên 2008

DECLARE @y VARCHAR(MAX) = REPLICATE(CAST('X' AS VARCHAR(MAX)),92681); 

SET @y = REPLICATE(@y,92681); 

SELECT LEN(@y) 

Returns

8589767761 

Tôi chạy này trên máy tính để bàn 32 bit của tôi vì vậy chuỗi 8GB đây là cách vượt quá bộ nhớ địa chỉ

Chạy

select internal_objects_alloc_page_count 
from sys.dm_db_task_space_usage 
WHERE session_id = @@spid 

trả lại

internal_objects_alloc_page_co 
------------------------------ 
2144456  

vì vậy tôi đoán tất cả điều này chỉ được lưu trữ trong LOB trang trong tempdb không có xác thực về độ dài. Tăng trưởng số lượng trang được liên kết với câu lệnh SET @y = REPLICATE(@y,92681);. Việc gán biến ban đầu cho @y và tính toán LEN không làm tăng điều này.

Lý do để đề cập đến điều này là do số lượng trang nhiều hơn tôi mong đợi. Giả sử một trang 8KB sau đó điều này làm việc tại 16,36 GB mà rõ ràng là nhiều hơn hoặc ít hơn gấp đôi những gì có vẻ là cần thiết. Tôi suy đoán rằng điều này có thể là do sự thiếu hiệu quả của hoạt động nối chuỗi cần phải sao chép toàn bộ chuỗi lớn và nối một đoạn vào cuối thay vì có thể thêm vào cuối chuỗi hiện có. Thật không may tại thời điểm .WRITE phương pháp isn't supported cho biến varchar (max).

Addition

Tôi cũng đã thử nghiệm hành vi với concatenating nvarchar(max) + nvarchar(max)nvarchar(max) + varchar(max). Cả hai đều cho phép vượt quá giới hạn 2GB. Sau đó cố gắng lưu trữ kết quả của điều này trong một bảng sau đó thất bại với thông báo lỗi Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes. một lần nữa. Các kịch bản cho rằng là dưới đây (có thể mất một thời gian dài để chạy).

DECLARE @y1 VARCHAR(MAX) = REPLICATE(CAST('X' AS VARCHAR(MAX)),2147483647); 
SET @y1 = @y1 + @y1; 
SELECT LEN(@y1), DATALENGTH(@y1) /*4294967294, 4294967292*/ 


DECLARE @y2 NVARCHAR(MAX) = REPLICATE(CAST('X' AS NVARCHAR(MAX)),1073741823); 
SET @y2 = @y2 + @y2; 
SELECT LEN(@y2), DATALENGTH(@y2) /*2147483646, 4294967292*/ 


DECLARE @y3 NVARCHAR(MAX) = @y2 + @y1 
SELECT LEN(@y3), DATALENGTH(@y3) /*6442450940, 12884901880*/ 

/*This attempt fails*/ 
SELECT @y1 y1, @y2 y2, @y3 y3 
INTO Test 
+0

Tuyệt vời - vì vậy nó sẽ xuất hiện rằng tài liệu đó là "không đầy đủ" - tôi lưu ý rằng trang thông thường đề cập đến "kích thước bộ nhớ" tối đa, có lẽ chỉ áp dụng cho các cột chứ không phải các biến. –

+0

@Damien - Chắc chắn sẽ xuất hiện theo cách đó. Không chắc chắn nếu có một số giới hạn khác có thể đạt được về tổng số trang nhưng tôi nghĩ rằng điều này được lưu trữ trong một cấu trúc cây B (dựa trên p.381 của SQL Server 2008 internals) vì vậy về nguyên tắc có thể được mở rộng chắc chắn. –

+0

@Damien_The_Unbeliever - [Tài liệu ở đây] (http://msdn.microsoft.com/en-us/library/ms345368.aspx) có vẻ phẳng ra sai dựa trên các thí nghiệm ở đây, nói khá rõ ràng rằng "Đối tượng lớn (LOB) biến kiểu dữ liệu và tham số ... loại có thể có kích thước tối đa 2 GB " –

9

EDIT: Sau khi điều tra thêm, giả định ban đầu của tôi mà đây là một lỗi bất thường (lỗi?) của cú pháp declare @var datatype = value không chính xác.

Tôi đã sửa đổi tập lệnh của bạn cho năm 2005 vì cú pháp đó không được hỗ trợ, sau đó thử phiên bản sửa đổi vào năm 2008. Năm 2005, tôi nhận được thông báo lỗi Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.. Trong năm 2008, kịch bản sửa đổi vẫn thành công.

declare @KMsg varchar(max); set @KMsg = REPLICATE('a',1024); 
declare @MMsg varchar(max); set @MMsg = REPLICATE(@KMsg,1024); 
declare @GMsg varchar(max); set @GMsg = REPLICATE(@MMsg,1024); 
declare @GGMMsg varchar(max); set @GGMMsg = @GMsg + @GMsg + @MMsg; 
select LEN(@GGMMsg) 
+0

Kịch bản luôn tạo ra lỗi (bằng cách cố gắng chèn bảng), nhưng vào năm 2008, tôi luôn nhận được một kết quả trong tập kết quả đầu tiên, cho biết biến không tồn tại và dài hơn 2^31-1 . –

+0

@Damien_The_Unbeliever: Tôi đã cắt tập lệnh xuống thành phần biến và bây giờ nhận được kết quả tương tự như bạn. Vào năm 2005, tôi nhận được lỗi 'Cố gắng phát triển ...' trên câu lệnh 'set @GGMMsg = ...'. Trong năm 2008, kịch bản thành công. –

Các vấn đề liên quan