varchar(max)变量的最大大小

时间:2011-09-30 13:52:55

标签: sql-server tsql

在过去的任何时候,如果有人问我varchar(max)的最大尺寸,我会说2GB,或者查找更准确的figure(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)。我有兴趣知道它是否适用于其他版本)

3 个答案:

答案 0 :(得分:67)

据我所知,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的{​​{1}}个页面中,没有验证长度。页数增长都与tempdb语句相关联。对SET @y = REPLICATE(@y,92681);@y计算的初始变量分配并没有增加这一点。

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

<强>加成

我还测试了连接.WRITEnvarchar(max) + nvarchar(max)的行为。这两个都允许超过2GB的限制。然后尝试将结果存储在表中,然后再次失败并返回错误消息nvarchar(max) + varchar(max)。该脚本如下(可能需要很长时间才能运行)。

Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.

答案 1 :(得分: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)

答案 2 :(得分:0)

在Oracle 10g的varchar中,您最多可以存储4000个字母。