Максимальный размер переменной varchar (max) - PullRequest
84 голосов
/ 30 сентября 2011

В любое время в прошлом, если бы кто-то спросил у меня максимальный размер для varchar(max), я бы сказал, 2 ГБ, или нашел бы более точную цифру (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)

Итак, теперь я знаю, что переменная может превышать барьер в 2 ГБ - кто-нибудь знает, каково действительное ограничение для переменной varchar(max)?


(Вышеупомянутый тест завершен на SQL Server 2008 (не R2). Мне было бы интересно узнать, применимо ли это к другим версиям)

Ответы [ 2 ]

68 голосов
/ 30 сентября 2011

Насколько я могу судить, в 2008 году не было верхнего предела.

В SQL Server 2005 ваш код не выполняется при назначении переменной @GGMMsg с

Попытка увеличить LOB за максимально допустимый размер в 2 147 483 647 байт.

приведенный ниже код завершается с

REPLICATE: длина результата превышает ограничение длины (2 ГБ) целевого большого типа.

Однако, похоже, эти ограничения были незаметно сняты.В 2008

DECLARE @y VARCHAR(MAX) = REPLICATE(CAST('X' AS VARCHAR(MAX)),92681); 

SET @y = REPLICATE(@y,92681);

SELECT LEN(@y) 

Возвращает

8589767761

Я запустил это на своем 32-битном настольном компьютере, так что эта строка 8 ГБ намного превышает адресную память

Работает

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);.Первоначальное присвоение переменной @y и расчет LEN не увеличили это.

Причина упоминания этого заключается в том, что количество страниц намного больше, чем я ожидал.Если предположить, что страница размером 8 КБ, то получается 16,36 ГБ, что, очевидно, более или менее вдвое больше, чем кажется необходимым.Я предполагаю, что это, скорее всего, связано с неэффективностью операции конкатенации строк, которая требует копирования всей огромной строки и добавления фрагмента в конец, а не возможности добавления в конец существующей строки.К сожалению, на данный момент .WRITE метод не поддерживается для переменных varchar (max).

Добавление

Я также тестировалповедение с конкатенацией nvarchar(max) + nvarchar(max) и nvarchar(max) + varchar(max).Оба из них позволяют превышать ограничение в 2 ГБ.Попытка затем сохранить результаты этого в таблице тогда терпит неудачу с сообщением об ошибке 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
9 голосов
/ 30 сентября 2011

РЕДАКТИРОВАТЬ : После дальнейшего изучения мое первоначальное предположение, что это была аномалия (ошибка?) Синтаксиса declare @var datatype = value, неверно.

С тех пор я изменил ваш скриптсинтаксис не поддерживается, затем попробовал модифицированную версию в 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...