ตั้งแต่varcharanyways จัดสรรพื้นที่แบบไดนามิกคำถามของฉันคือไม่ว่าจะใช้มีประสิทธิภาพมากขึ้นหรือประหยัดพื้นที่มากขึ้นเมื่อเทียบกับการใช้varchar(255) varchar(5000)ถ้าใช่ทำไม
ตั้งแต่varcharanyways จัดสรรพื้นที่แบบไดนามิกคำถามของฉันคือไม่ว่าจะใช้มีประสิทธิภาพมากขึ้นหรือประหยัดพื้นที่มากขึ้นเมื่อเทียบกับการใช้varchar(255) varchar(5000)ถ้าใช่ทำไม
คำตอบ:
ใช่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)
rowcount*(column_size/2)มันเป็นเพียงแค่การทำงานของ