2011-09-30 37 views
76

En cualquier momento en el pasado, si alguien me hubiera preguntado el tamaño máximo para varchar(max), habría dicho 2GB, o busqué una más exacta figure (2^31- 1, o 2147483647).Tamaño máximo de una varchar (max) variable

Sin embargo, en algunas pruebas recientes, he descubierto que varchar(max) variables que al parecer pueden superar este tamaño:

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 

Resultados:

(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) 

Por lo tanto, teniendo en cuenta que ahora sé que una variable puede superar la barrera de 2 GB: ¿alguien sabe cuál es el límite real para una variable varchar(max)?


(. Por encima de la prueba finalizado en SQL Server 2008 (no R2) Me interesaría saber si se aplica a otras versiones)

+0

'declare @x varchar (max) = 'XX'; SELECT LEN (REPLICATE (@ x, 2147483647)) 'da' 4294967294', pero tarda mucho tiempo en ejecutarse, incluso después de que ha regresado el 'SELECT', por lo que no estoy seguro de qué tiempo extra dedico a hacerlo. –

Respuesta

62

Por lo que yo puedo decir que no hay límite superior en 2008.

En SQL Server 2005 el código en su pregunta falla en la asignación a la variable @GGMMsg con

Intentando para crecer LOB más allá del tamaño máximo permitido de 2,147,483,647 bytes.

el código de abajo falla con

REPLICATE: La longitud del resultado excede el límite de longitud de (2 GB) de la gran tipo de destino.

Sin embargo, parece que estas limitaciones se han levantado silenciosamente.En 2008

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

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

SELECT LEN(@y) 

devoluciones

8589767761 

me encontré con esto en mi máquina de escritorio de 32 bits por lo que esta cadena de 8 GB es la forma en exceso de memoria direccionable

Correr

select internal_objects_alloc_page_count 
from sys.dm_db_task_space_usage 
WHERE session_id = @@spid 

devueltos

internal_objects_alloc_page_co 
------------------------------ 
2144456  

así que supongo que todo esto se almacena en LOB páginas en tempdb sin validación de longitud. El crecimiento del conteo de páginas estuvo asociado con la declaración SET @y = REPLICATE(@y,92681);. La asignación de variable inicial a @y y el cálculo LEN no aumentó esto.

La razón para mencionar esto es porque el número de páginas es mucho más de lo que esperaba. Asumiendo una página de 8KB, esto da un resultado de 16.36 GB, lo que obviamente es más o menos el doble de lo que parece ser necesario. Supongo que esto se debe probablemente a la ineficacia de la operación de concatenación de cadenas que necesita copiar toda la cadena enorme y agregar un fragmento al final en lugar de poder agregarlo al final de la cadena existente. Lamentablemente, en este momento el .WRITE método isn't supported para variables varchar (max).

adición

También hemos probado el comportamiento con la concatenación de nvarchar(max) + nvarchar(max) y nvarchar(max) + varchar(max). Ambos permiten superar el límite de 2 GB. Sin embargo, intentar almacenar los resultados de esto en una tabla falla pero con el mensaje de error Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes. nuevamente. La secuencia de comandos para eso está debajo (puede tomar mucho tiempo para ejecutarse).

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 
+0

Excelente, por lo que parece que la documentación es bastante "incompleta". Observo que la página habitual se refiere a un "tamaño de almacenamiento" máximo, que presumiblemente solo se aplica a columnas, no a variables. –

+0

@Damien - Definitivamente aparece de esa manera. No estoy seguro de si hay algún otro límite que pueda alcanzarse en términos del número total de páginas, pero creo que está almacenado en una estructura de árbol B (basada en la p.381 de las partes internas de SQL Server 2008), por lo que en principio podría extenderse definitivamente. –

+0

@Damien_The_Unbeliever - [La documentación aquí] (http://msdn.microsoft.com/en-us/library/ms345368.aspx) parece completamente incorrecta en función de los experimentos aquí, indicando bastante inequívocamente que "objeto grande (LOB)" tipo de datos variables y parámetros ... los tipos pueden tener hasta 2 GB de tamaño " –

9

EDITAR: Después de investigaciones adicionales, mi suposición original que esta fue una anomalía (¿error?) de la sintaxis declare @var datatype = value incorrecta.

Modifiqué su secuencia de comandos para 2005 ya que esa sintaxis no es compatible, luego intenté con la versión modificada en 2008. En 2005, aparece el mensaje de error Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes.. En 2008, el script modificado sigue siendo exitoso.

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) 
+0

La secuencia de comandos siempre produce un error (al tratar de insertar la tabla), pero en 2008, siempre obtengo un resultado en el primer conjunto de resultados, lo que indica que la variable existe, y es más larga que 2^31-1 de longitud . –

+0

@Damien_The_Unbeliever: Corté el script solo para la parte variable y ahora obtengo los mismos resultados que tú. En 2005, aparece el error 'Intento de crecer ...' en la declaración 'set @GGMMsg = ...'. En 2008, el guión es exitoso. –

Cuestiones relacionadas