varchar(max)变量的最大大小

Dam*_*ver 87 t-sql sql-server

在过去的任何时候,如果有人问我a的最大尺寸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
Run Code Online (Sandbox Code Playgroud)

结果:

(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)
Run Code Online (Sandbox Code Playgroud)

所以,鉴于我现在知道一个变量可以超过2GB的障碍 - 有谁知道varchar(max)变量的实际限制是多少?


(上面的测试在SQL Server 2008上完成(不是R2).我有兴趣知道它是否适用于其他版本)

Mar*_*ith 70

据我所知,2008年没有上限.

在SQL Server 2005中,您的问题中的代码无法分配给@GGMMsg变量

试图将LOB增加到超过允许的最大大小2,147,483,647字节.

下面的代码失败了

REPLICATE:结果的长度超过目标大型的长度限制(2GB).

然而,似乎这些局限性已经悄然解除.2008年

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

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

SELECT LEN(@y) 
Run Code Online (Sandbox Code Playgroud)

返回

8589767761
Run Code Online (Sandbox Code Playgroud)

我在我的32位台式机上运行这个,所以这8GB字符串超出了可寻址内存

运行

select internal_objects_alloc_page_count
from sys.dm_db_task_space_usage
WHERE session_id = @@spid
Run Code Online (Sandbox Code Playgroud)

internal_objects_alloc_page_co 
------------------------------ 
2144456    
Run Code Online (Sandbox Code Playgroud)

所以我认为这一切都只是存储在LOB页面中tempdb而没有长度验证.页数增长都与SET @y = REPLICATE(@y,92681);语句相关联.初始变量赋值@yLEN计算没有增加这个.

提到这个的原因是因为页数远远超过我的预期.假设一个8KB的页面,那么这个数据的计算结果为16.36 GB,这显然或多或少是看似必要的两倍.我推测这可能是由于字符串连接操作的低效率需要复制整个大字符串并将一个块附加到末尾而不是能够添加到现有字符串的末尾.不幸的是,目前varchar(max)变量不支持.WRITE方法.

加成

我也用连接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
Run Code Online (Sandbox Code Playgroud)


Joe*_*lli 9

编辑:经过进一步调查,我最初的假设,这是一个异常(错误?)的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)
Run Code Online (Sandbox Code Playgroud)