varchar(max)变量的最大大小


88

在过去的任何时候,如果有人问我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

结果:

(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)上完成。我想知道它是否适用于其他版本)


declare @x varchar(max) = 'XX'; SELECT LEN(REPLICATE(@x,2147483647))4294967294我的钱,但是需要花费很长的时间-即使在SELECT回来之后,也不能确定多余的时间在做什么。
马丁·史密斯

Answers:


73

据我所知,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    

所以我认为所有这些都只是存储在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

1
太好了-文件似乎显得“不完整”-我注意到通常的页面指的是最大的“存储大小”,它大概仅适用于列,而不适用于变量。
Damien_The_Unbeliever 2011年

@Damien-肯定是那样。不知道在页面总数方面是否可以达到其他限制,但是我认为这是以B树结构存储的(基于SQL Server 2008内部的p.381),因此原则上可以肯定地扩展。
马丁·史密斯,

@Damien_The_Unbeliever- 根据此处的实验,这里的文档似乎是完全错误的,它明确指出“大对象(LOB)数据类型变量和参数...类型的大小最大为2 GB”
Martin Smith

有点没用,但有趣。理论上,您可以用一个变量填充磁盘... :-)
gbn

我这里有些犹豫,因为将值存储在变量中与将其存储在列中不同。您是否想用一列尝试这样做?或者您有更新吗?varchar只要您不尝试将其放入变量或varchar列中,甚至SQL Server 2000的文字字符串中的值都可以超过8000个字符。
ErikE 2013年

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)

该脚本始终会产生错误(尝试插入表),但是在2008年,我总是在第一个结果集中得到一个结果,表明该变量确实存在,并且长度大于2 ^ 31-1。
Damien_The_Unbeliever 2011年

@Damien_The_Unbeliever:我将脚本缩减为可变部分,现在得到与您相同的结果。在2005年,我收到Attempting to grow...set @GGMMsg=...语句的错误。在2008年,该脚本成功。
Joe Stefanelli
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.