【问题标题】:Maximum size of a varchar(max) variablevarchar(max) 变量的最大大小
【发布时间】:2011-09-30 13:52:54
【问题描述】:

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

【问题讨论】:

  • declare @x varchar(max) = 'XX'; SELECT LEN(REPLICATE(@x,2147483647)) 为我提供了4294967294,但需要很长时间才能运行 - 即使在SELECT 已返回之后,所以不确定额外的时间花在做什么上。

标签: sql-server tsql


【解决方案1】:

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

所以我认为这一切都只是存储在tempdbLOB 页面中,没有长度验证。页数增长都与SET @y = REPLICATE(@y,92681); 语句相关。对@y 的初始变量分配和LEN 的计算并没有增加这一点。

之所以提到这一点,是因为页数比我预期的要多得多。假设一个 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

【讨论】:

  • 优秀 - 所以看起来文档相当“不完整” - 我注意到通常的页面是指最大“存储大小”,它可能只适用于列,而不是变量。跨度>
  • @Damien - 绝对是那样的。不确定在总页数方面是否可以达到其他限制,但我认为这存储在 B 树结构中(基于 SQL Server 2008 内部的 p.381),因此原则上可以肯定地扩展。
  • @Damien_The_Unbeliever - The documentation here 似乎完全错误,根据这里的实验,相当明确地指出“大对象 (LOB) 数据类型变量和参数......类型可以高达 2 GB大小”
  • 有点没用但很有趣。从理论上讲,您可以用一个变量填充磁盘... :-)
  • 我在这里有些犹豫,因为将值存储在变量中与将值存储在列中不同。您是否想尝试使用专栏来代替 - 或者您有更新吗?甚至 SQL Server 2000 的代码中文字字符串中的 varchar 值也可能超过 8000 个字符,只要您没有尝试将其放入变量或 varchar 列中。
【解决方案2】:

编辑:经过进一步调查,我最初认为这是 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:我将脚本缩减为仅可变部分,现在得到与您相同的结果。在 2005 年,我在 set @GGMMsg=... 语句中收到了 Attempting to grow... 错误。 2008年,剧本成功。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
  • 2021-12-01
相关资源
最近更新 更多