[sql-server] varchar (max) 변수의 최대 크기

과거에 누군가 나에게 .NET의 최대 크기를 물었다 varchar(max)면 2GB라고 말했거나 더 정확한 수치 (2 ^ 31-1 또는 2147483647)를 찾아봤을 것 입니다.

그러나 최근 테스트에서 varchar(max)변수가 분명히이 크기를 초과 할 수 있음을 발견했습니다 .

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

결과 :

(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)

이제 변수 가 2GB 장벽을 초과 할 수 있다는 것을 알고 있다면 변수 의 실제 제한이 무엇인지 아는 사람이 varchar(max)있습니까?


(위의 테스트는 SQL Server 2008 (R2 아님)에서 완료되었습니다. 다른 버전에도 적용되는지 알고 싶습니다.)



답변

내가 말할 수있는 한 2008 년에는 상한선이 없습니다.

SQL Server 2005에서 질문의 코드는 다음 @GGMMsg과 같은 변수 할당에 실패합니다.

허용되는 최대 크기 인 2,147,483,647 바이트를 초과하여 LOB를 늘리려 고합니다.

아래 코드는 실패합니다

REPLICATE : 결과 길이가 대상 대형 유형의 길이 제한 (2GB)을 초과합니다.

그러나 이러한 제한은 조용히 해제 된 것으로 보입니다. 2008 년

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

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

SELECT LEN(@y)

보고

8589767761

32 비트 데스크톱 컴퓨터에서 실행 했으므로이 8GB 문자열은 주소 지정 가능한 메모리를 초과합니다.

달리는

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

반환 됨

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

그래서이 모든 것이 길이에 대한 유효성 검사없이 LOB페이지에 저장된다고 가정합니다 tempdb. 페이지 수 증가는 모두 SET @y = REPLICATE(@y,92681);진술 과 관련이 있습니다. 초기 변수 할당 @yLEN계산은 이것을 증가시키지 않았습니다.

이것을 언급하는 이유는 페이지 수가 내가 예상했던 것보다 훨씬 많기 때문입니다. 8KB 페이지를 가정하면 16.36GB에서 작동하며 이는 분명히 필요한 것보다 두 배 더 많거나 적습니다. 나는 이것이 기존 문자열의 끝에 추가 할 수있는 것이 아니라 전체 거대한 문자열을 복사하고 끝에 청크를 추가해야하는 문자열 연결 작업의 비 효율성 때문이라고 추측합니다. 불행히도 현재이 .WRITE메서드 varchar (max) 변수에 대해 지원되지 않습니다 .

부가

또한 연결 nvarchar(max) + nvarchar(max)nvarchar(max) + varchar(max). 둘 다 2GB 제한을 초과 할 수 있습니다. 이 결과를 테이블에 저장하려고하면 실패하지만 오류 메시지가 Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.다시 표시 됩니다. 이에 대한 스크립트는 다음과 같습니다 (실행하는 데 시간이 오래 걸릴 수 있음).

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


답변

편집 : 추가 조사 후 이것이 declare @var datatype = value구문 의 이상 (버그?)이라는 원래 가정 이 잘못되었습니다.

해당 구문이 지원되지 않기 때문에 2005 년에 대한 스크립트를 수정 한 다음 2008 년에 수정 된 버전을 시도했습니다. 2005 년에 Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.오류 메시지가 나타납니다. 2008 년에도 수정 된 스크립트는 여전히 성공적입니다.

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)


답변