ขนาดสูงสุดของตัวแปร varchar (สูงสุด)


90

เมื่อใดก็ตามที่ผ่านมาหากมีคนถามฉันว่าขนาดสูงสุดของ a 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) ฉันสนใจที่จะทราบว่าสามารถใช้กับเวอร์ชันอื่นได้หรือไม่)


declare @x varchar(max) = 'XX'; SELECT LEN(REPLICATE(@x,2147483647))ให้4294967294สำหรับฉัน แต่ใช้เวลาวิ่งนาน - แม้SELECTจะกลับมาแล้วก็เลยไม่แน่ใจว่าจะใช้เวลาเพิ่มไปทำอะไร
Martin Smith

คำตอบ:


75

เท่าที่ฉันสามารถบอกได้ว่าไม่มีขีด จำกัด สูงสุดในปี 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เพจtempdbโดยไม่มีการตรวจสอบความยาว การเติบโตของการนับหน้าทั้งหมดเกี่ยวข้องกับSET @y = REPLICATE(@y,92681);คำสั่ง การกำหนดตัวแปรเริ่มต้นให้@yและการLENคำนวณไม่ได้เพิ่มสิ่งนี้

เหตุผลที่พูดถึงเรื่องนี้เป็นเพราะจำนวนหน้ามากกว่าที่ฉันคาดไว้อย่างมหาศาล สมมติว่าหน้า 8KB จะทำงานได้ที่ 16.36 GB ซึ่งเห็นได้ชัดว่าสิ่งที่ดูเหมือนจะจำเป็นมากหรือน้อยกว่าสองเท่า ฉันคาดเดาว่าสิ่งนี้น่าจะเกิดจากความไม่มีประสิทธิภาพของการดำเนินการต่อสตริงที่จำเป็นต้องคัดลอกสตริงขนาดใหญ่ทั้งหมดและต่อท้ายส่วนท้ายแทนที่จะสามารถเพิ่มลงในส่วนท้ายของสตริงที่มีอยู่ได้ ขออภัยในขณะนี้.WRITEวิธีนี้ไม่รองรับตัวแปร varchar (สูงสุด)

ส่วนที่เพิ่มเข้าไป

ฉันได้ทดสอบพฤติกรรมด้วยการเชื่อมต่อ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

1
ยอดเยี่ยม - ดังนั้นดูเหมือนว่าเอกสารจะค่อนข้าง "ไม่สมบูรณ์" - ฉันทราบว่าหน้าปกติอ้างถึง "ขนาดพื้นที่เก็บข้อมูล" สูงสุดซึ่งน่าจะใช้ได้กับคอลัมน์เท่านั้นไม่ใช่ตัวแปร
Damien_The_Unbeliever

@Damien - ปรากฎแบบนั้นแน่นอน ไม่แน่ใจว่ามีขีด จำกัด อื่นที่สามารถเข้าถึงได้ในแง่ของจำนวนหน้าทั้งหมดหรือไม่ แต่ฉันคิดว่าสิ่งนี้ถูกเก็บไว้ในโครงสร้างต้นไม้ B (ตามหน้า 381 ของ SQL Server 2008 ภายใน) ดังนั้นโดยหลักการแล้วสามารถขยายได้อย่างแน่นอน
Martin Smith

@Damien_The_Unbeliever - เอกสารที่นี่ดูเหมือนจะไม่ถูกต้องตามการทดลองที่นี่โดยระบุอย่างไม่น่าสงสัยว่า "ตัวแปรและพารามิเตอร์ประเภทข้อมูลวัตถุขนาดใหญ่ (LOB) ... ประเภทมีขนาดได้สูงสุด 2 GB"
Martin Smith

ไร้ประโยชน์ แต่ก็น่าสนใจ ในทางทฤษฎีคุณสามารถเติมดิสก์ด้วยตัวแปรเดียว ... :-)
gbn

ฉันมีความลังเลที่นี่เนื่องจากการจัดเก็บค่าในตัวแปรไม่เหมือนกับการจัดเก็บในคอลัมน์ คุณรู้สึกอยากลองใช้คอลัมน์นี้แทน - หรือคุณมีการอัปเดต แม้แต่ SQL Server 2000 ก็สามารถมีvarcharค่าที่ยาวกว่า 8000 อักขระในสตริงตามตัวอักษรในโค้ดได้ตราบใดที่คุณไม่ได้พยายามใส่ไว้ในตัวแปรหรือvarcharคอลัมน์
ErikE

9

แก้ไข : หลังจากการตรวจสอบเพิ่มเติมสมมติฐานเดิมของฉันที่ว่านี่เป็นความผิดปกติ (ข้อบกพร่อง?) ของdeclare @var datatype = valueไวยากรณ์ไม่ถูกต้อง

ฉันแก้ไขสคริปต์ของคุณสำหรับปี 2005 เนื่องจากไม่รองรับไวยากรณ์นั้นจากนั้นลองใช้เวอร์ชันที่แก้ไขในปี 2008 ในปี 2548 ฉันได้รับ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

@Damien_The_Unbeliever: ฉันตัดสคริปต์ลงเหลือแค่ส่วนตัวแปรและตอนนี้ก็ได้ผลลัพธ์เช่นเดียวกับคุณ ในปี 2548 ฉันได้รับAttempting to grow...ข้อผิดพลาดในset @GGMMsg=...คำสั่ง ในปี 2008 สคริปต์ประสบความสำเร็จ
Joe Stefanelli
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.