การใช้ varchar (5,000) จะไม่ดีเมื่อเทียบกับ varchar (255)


28

ตั้งแต่varcharanyways จัดสรรพื้นที่แบบไดนามิกคำถามของฉันคือไม่ว่าจะใช้มีประสิทธิภาพมากขึ้นหรือประหยัดพื้นที่มากขึ้นเมื่อเทียบกับการใช้varchar(255) varchar(5000)ถ้าใช่ทำไม


คุณต้องการคอลัมน์กว้าง 5,000 ตัวอักษรหรือไม่ ถ้าเป็นเช่นนั้นทำไม คอลัมน์ varchar (MAX) จะดีกว่าสำหรับคุณที่นี่หรือไม่
Richard L. Dawson

คำตอบ:


52

ใช่varchar(5000)สามารถเลวร้ายยิ่งกว่าvarchar(255)ถ้าค่าทั้งหมดจะพอดีกับหลัง สาเหตุคือ SQL Server จะประมาณขนาดข้อมูลและในทางกลับกันหน่วยความจำจะให้สิทธิ์ตามขนาดที่ประกาศ (ไม่ใช่ขนาดจริง ) ของคอลัมน์ในตาราง เมื่อคุณมีvarchar(5000)ก็จะถือว่าทุกค่ามีความยาว 2,500 ตัวอักษรและสำรองหน่วยความจำตามที่

นี่คือตัวอย่างจากการนำเสนอ GroupBy ล่าสุดของฉันเกี่ยวกับนิสัยที่ไม่ดีที่ทำให้ง่ายต่อการพิสูจน์ด้วยตัวคุณเอง (ต้องการ SQL Server 2016 สำหรับsys.dm_exec_query_statsคอลัมน์ผลลัพธ์บางส่วนแต่ควรจะพิสูจน์ได้ด้วยSET STATISTICS TIME ONเครื่องมืออื่น ๆ มันแสดงให้เห็นถึงหน่วยความจำขนาดใหญ่และ runtimes อีกต่อไปสำหรับแบบสอบถามเดียวกันกับข้อมูลเดียวกัน - ความแตกต่างเพียงอย่างเดียวคือขนาดที่ประกาศของคอลัมน์:

-- create three tables with different column sizes
CREATE TABLE dbo.t1(a nvarchar(32),   b nvarchar(32),   c nvarchar(32),   d nvarchar(32));
CREATE TABLE dbo.t2(a nvarchar(4000), b nvarchar(4000), c nvarchar(4000), d nvarchar(4000));
CREATE TABLE dbo.t3(a nvarchar(max),  b nvarchar(max),  c nvarchar(max),  d nvarchar(max));
GO -- that's important

-- Method of sample data pop : irrelevant and unimportant.
INSERT dbo.t1(a,b,c,d)
  SELECT TOP (5000) LEFT(name,1), RIGHT(name,1), ABS(column_id/10), ABS(column_id%10)
  FROM sys.all_columns ORDER BY object_id;
GO 100
INSERT dbo.t2(a,b,c,d) SELECT a,b,c,d FROM dbo.t1;
INSERT dbo.t3(a,b,c,d) SELECT a,b,c,d FROM dbo.t1;
GO

-- no "primed the cache in advance" tricks
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
GO

-- Redundancy in query doesn't matter! Just has to create need for sorts etc.
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t1 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t2 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t3 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO

SELECT [table] = N'...' + SUBSTRING(t.[text], CHARINDEX(N'FROM ', t.[text]), 12) + N'...', 
s.last_dop, s.last_elapsed_time, s.last_grant_kb, s.max_ideal_grant_kb
FROM sys.dm_exec_query_stats AS s CROSS APPLY sys.dm_exec_sql_text(s.sql_handle) AS t
WHERE t.[text] LIKE N'%dbo.'+N't[1-3]%' ORDER BY t.[text];

ดังนั้นใช่ขนาดคอลัมน์ของคุณได้โปรด

นอกจากนี้ฉันเรียกใช้การทดสอบอีกครั้งด้วย varchar (32), varchar (255), varchar (5,000), varchar (8000) และ varchar (สูงสุด) ผลลัพธ์ที่คล้ายกัน ( คลิกเพื่อดูภาพขยาย ) แม้ว่าความแตกต่างระหว่าง 32 และ 255 และระหว่าง 5,000 และ 8,000 นั้นไม่มีความสำคัญ:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือการทดสอบอื่นที่มีการTOP (5000)เปลี่ยนแปลงสำหรับการทดสอบที่ทำซ้ำได้อย่างสมบูรณ์มากขึ้นที่ฉันถูก badgered อย่างไม่หยุดหย่อนเกี่ยวกับ ( คลิกเพื่อดูภาพขยาย ):

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นแม้จะมี 5,000 แถวแทน 10,000 แถว (และมี 5,000 + แถวใน sys.all_columns อย่างน้อยไกลกลับเป็น SQL Server 2008 R2) ความคืบหน้าค่อนข้างเป็นที่สังเกตเชิงเส้น - แม้จะมีข้อมูลเดียวกันที่มีขนาดใหญ่กำหนดขนาด ของคอลัมน์จำเป็นต้องใช้หน่วยความจำและเวลามากขึ้นเพื่อตอบสนองการค้นหาเดียวกันที่แน่นอน (แม้ว่าจะไม่มีความหมายDISTINCT)


มันน่าประหลาดใจจริงๆ ความแตกต่างระหว่างvarchar(450)และvarchar(255)จะเหมือนกันหรือไม่ (หรืออะไรที่ต่ำกว่า 4000)
a_horse_with_no_name

@a_horse_with_no_name ฉันไม่ได้ทดสอบพีชคณิตทั้งหมดของประสิทธิภาพการทำงานรันไทม์ แต่ทุนหน่วยความจำจะเป็นความก้าวหน้าเชิงเส้น - rowcount*(column_size/2)มันเป็นเพียงแค่การทำงานของ
Aaron Bertrand

มันค่อนข้างน่าผิดหวัง ฉันคิดว่า SQL Server รุ่นที่ทันสมัยจะไม่ได้รับผลกระทบนั้น (ตราบใดที่ความยาวที่กำหนดมีขนาดเล็กกว่านั้นคือ 8000 หรืออาจ 4000)
a_horse_with_no_name

1
@a_horse_with_no_name เอาล่ะมันจะต้องเดาได้ว่าขนาดของข้อมูลนั้นกว้างแค่ไหนเพื่อหลีกเลี่ยงการรั่วไหล มันควรจะเดาอย่างอื่นได้อย่างไร มันไม่สามารถสแกนและอ่านตารางทั้งหมดเพื่อกำหนดความยาวเฉลี่ยของ avg / max ของคอลัมน์ความกว้างแปรผันทั้งหมดในฐานะที่เป็นสารตั้งต้นในการสร้างแผนการดำเนินการ (และแม้ว่าจะทำได้
Aaron Bertrand

2
Oracle เก็บสถิติเกี่ยวกับเช่นความยาวแถวเฉลี่ยค่า min และ max สำหรับแต่ละคอลัมน์รวมถึงฮิสโตแกรม Postgres เก็บสถิติที่คล้ายกันมาก (มันไม่ได้บันทึกขั้นต่ำ / สูงสุด แต่เป็นความถี่) สำหรับทั้งคู่ไม่มีความแตกต่างใด ๆ ระหว่าง nvarchar (150), nvarchar (2000) หรือ varchar (400)
a_horse_with_no_name
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.