varchar(max)variables的最大大小

在过去的任何时候,如果有人问我varchar(max)的最大大小,我会说2GB,或者查找更准确的数字 (2 ^ 31-1或2147483647)。

但是,在最近的一些testing中,我发现varchar(max)variables显然可以超过这个大小:

 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) 

所以,鉴于我现在知道一个variables可以超过2GB的障碍 – 有没有人知道什么是一个varchar(max)variables的实际限制?


(以上testing在SQL Server 2008上完成(不是R2),我想知道它是否适用于其他版本)

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

在SQL Server 2005中,您问题中的代码在使用@GGMMsgvariables时失败

试图增长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位桌面机器上运行这个8GBstring的方式超出了可寻址内存

运行

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

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

所以我认为这一切都只是被存储在tempdb中的LOB页面上,没有长度validation。 页数增长都与SET @y = REPLICATE(@y,92681); 声明。 @y的初始variables赋值和LEN计算没有增加这个值。

提到这个的原因是因为页数比我预期的要多得多。 假设一个8KB的页面,那么这个16.36 GB的内存就显得多了或less一些,似乎是必要的。 我推测这可能是由于string连接操作的效率低下需要复制整个巨大的string,并追加一个块到最后,而不是能够添加到现有string的末尾。 不幸的是,目前.WRITE方法不支持 varchar(max)variables。

加成

我还testing了连接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 

编辑 :经过进一步调查,我原来的假设,这是一个exception(bug?)的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)