Sql server varchar(max)变量的最大大小

Sql server varchar(max)变量的最大大小,sql-server,tsql,Sql Server,Tsql,在过去的任何时候,如果有人问我一个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) = REPL

在过去的任何时候,如果有人问我一个
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)上完成的。我想知道它是否适用于其他版本)

EDIT:经过进一步调查,我最初认为这是
declare@var datatype=value
语法的异常(bug?)是不正确的

我修改了您2005年的脚本,因为该语法不受支持,然后在2008年尝试了修改后的版本。2005年,我收到
试图将LOB扩展到2147483647字节的最大允许大小之外。
错误消息。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年没有上限

在SQL Server 2005中,问题中的代码在分配给
@GGMMsg
变量时失败

正在尝试将LOB增长到超出允许的最大大小2147483647 字节

下面的代码在以下情况下失败:

复制:结果的长度超过的长度限制(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    
因此,我假设这一切只是存储在
tempdb
LOB
页面中,没有验证长度。页面计数的增长都与
SET@y=REPLICATE(@y,92681)有关语句。对
@y
的初始变量赋值和
LEN
计算没有增加这一点

之所以提到这一点,是因为页面数量远远超过了我的预期。假设一个8KB的页面,那么它的计算结果是16.36GB,这显然是看起来需要的两倍。我推测这可能是因为字符串连接操作效率低下,需要复制整个巨大的字符串并在末尾追加一个块,而不能添加到现有字符串的末尾。不幸的是,目前varchar(max)变量的
.WRITE
方法

添加

我还测试了连接
nvarchar(max)+nvarchar(max)
nvarchar(max)+varchar(max)
的行为。这两者都允许超过2GB限制。然后尝试将此结果存储在表中,但失败,错误消息为
尝试将LOB增长到2147483647字节的最大允许大小之外。
再次。脚本如下(可能需要很长时间才能运行)


声明@x varchar(max)='XX';SELECT LEN(REPLICATE(@x,2147483647))
为我提供了
4294967294
,但运行时间很长-即使在
SELECT
返回后,也不确定额外的时间花在了什么上。脚本总是产生错误(通过尝试插入表),但在2008年,我总是在第一个结果集中得到一个结果,表示变量确实存在,并且长度超过2^31-1。@Damien_the_unsiever:我将脚本缩减为变量部分,现在得到与您相同的结果。2005年,我在
set@GGMMsg=…
语句中遇到了
尝试增长…
错误。在2008年,脚本成功了。非常好-因此文档似乎相当“不完整”-我注意到通常的页面引用了最大“存储大小”,这可能只适用于列,而不适用于变量。@Damien-显然是这样的。不确定在总页数方面是否还有其他限制,但我认为它存储在B树结构中(基于SQL Server 2008内部的p.381),因此原则上可以明确扩展。@Damien_不相信者-根据这里的实验,似乎完全错了,相当明确地指出“大型对象(LOB)数据类型变量和参数。。。类型的大小最多可达2 GB“有点没用,但很有趣。理论上,您可以用一个变量填充磁盘…:-)我在这里有些犹豫,因为在变量中存储值与在列中存储值不同。你想用一个专栏来代替它吗?或者你有更新吗?即使是SQL Server 2000在代码中的文字字符串中也可能有长度超过8000个字符的
varchar
值,只要您不尝试将其放入变量或
varchar
列中。
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