Karena bagaimanapun varchar
mengalokasikan ruang secara dinamis, pertanyaan saya adalah apakah menggunakan varchar(255)
lebih efisien atau menghemat lebih banyak ruang daripada menggunakan varchar(5000)
. Jika ya, mengapa?
Karena bagaimanapun varchar
mengalokasikan ruang secara dinamis, pertanyaan saya adalah apakah menggunakan varchar(255)
lebih efisien atau menghemat lebih banyak ruang daripada menggunakan varchar(5000)
. Jika ya, mengapa?
Jawaban:
Ya, varchar(5000)
bisa lebih buruk daripada varchar(255)
jika semua nilai cocok dengan yang terakhir. Alasannya adalah bahwa SQL Server akan memperkirakan ukuran data dan, pada gilirannya, hibah memori berdasarkan ukuran kolom yang dinyatakan (tidak aktual ) dalam sebuah tabel. Jika sudah varchar(5000)
, Anda akan menganggap bahwa setiap nilai sepanjang 2.500 karakter, dan mencadangkan memori berdasarkan itu.
Berikut ini adalah demo dari presentasi GroupBy saya baru-baru ini tentang kebiasaan buruk yang membuatnya mudah untuk dibuktikan sendiri (memerlukan SQL Server 2016 untuk beberapa sys.dm_exec_query_stats
kolom output, tetapi masih harus dapat dibuktikan dengan SET STATISTICS TIME ON
atau alat lain pada versi sebelumnya); itu menunjukkan memori lebih besar dan runtimes lebih lama untuk permintaan yang sama terhadap data yang sama - satu-satunya perbedaan adalah ukuran kolom yang dinyatakan:
-- 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];
Jadi, ya, ukuran kolom Anda benar , tolong.
Juga, saya menjalankan kembali tes dengan varchar (32), varchar (255), varchar (5000), varchar (8000), dan varchar (maks). Hasil serupa ( klik untuk memperbesar ), meskipun perbedaan antara 32 dan 255, dan antara 5.000 dan 8.000, dapat diabaikan:
Berikut ini adalah tes lain dengan TOP (5000)
perubahan untuk tes yang sepenuhnya dapat direproduksi yang sedang saya ganggu terus-menerus ( klik untuk memperbesar ):
Jadi, bahkan dengan 5.000 baris, bukan 10.000 baris (dan ada 5.000+ baris di sys.all_columns setidaknya sejauh SQL Server 2008 R2), perkembangan yang relatif linier diamati - bahkan dengan data yang sama, semakin besar ukuran yang ditentukan dari kolom, semakin banyak memori dan waktu yang diperlukan untuk memenuhi permintaan yang sama persis (bahkan jika itu tidak memiliki arti DISTINCT
).
varchar(450)
dan varchar(255)
sama? (Atau apa pun di bawah 4000?)
rowcount*(column_size/2)
.