2011-09-30 95 views
76

在过去的任何时候,如果有人问我最大尺寸为varchar(max),我会说2GB,或者查找更精确的figure(2^31- 1或2147483647)。varchar(max)变量的最大尺寸

然而,在最近的一些测试,我发现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)对我有兴趣知道它是否适用于其他版本)

+0

'declare @x varchar(max)='XX'; SELECT LEN(REPLICATE(@ x,2147483647))给出了'4294967294',但需要很长时间才能运行 - 即使在SELECT语句返回后,我们也不知道花了多少时间。 –

回答

62

据我可以告诉有在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) 

返回

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  

所以我认为这一切都只存储在LOBtempdb没有验证的长度。页数增长全部与SET @y = REPLICATE(@y,92681);声明有关。初始变量赋值为@yLEN的计算没有增加这个。

提到这个的原因是因为页数远远超过了我的预期。假设一个8KB的页面,那么这将在16.36 GB,这显然是或多或少是似乎是必要的两倍。我推测这可能是由于字符串连接操作的低效率需要复制整个巨大字符串并将块附加到最后而不是能够添加到现有字符串的末尾。不幸的是,此刻.WRITE方法isn't supported用于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 
+0

优秀 - 所以看起来文档相当“不完整” - 我注意到通常的页面是指最大的“存储大小”,这大概只适用于列,而不是变量。 –

+0

@Damien - 肯定会出现这种情况。不知道是否有一些其他的页面总数可以达到的限制,但我认为这是存储在B树结构中的(基于SQL Server 2008内部的第381页),因此原则上可以明确扩展。 –

+0

@Damien_The_Unbeliever - [这里的文档](http://msdn.microsoft.com/en-us/library/ms345368.aspx)基于这里的实验似乎是错误的,明确地指出“大对象(LOB)数据类型变量和参数...类型最大可达2 GB“ –

9

编辑:经过进一步调查,我原来的假设这是declare @var datatype = value语法的一个异常(bug?)是不正确的。

由于不支持该语法,因此我修改了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) 
+0

脚本总是产生一个错误(通过尝试执行表插入),但在2008年,我总是在第一个结果集中得到一个结果,表明该变量确实存在,并且长度超过2^31-1 。 –

+0

@Damien_The_Unbeliever:我将剧本剪辑为可变部分,现在得到与您相同的结果。在2005年,我在'set @GGMMsg = ...'语句中得到'试图增长...'错误。 2008年,剧本成功。 –