Yana varchar
zaten dinamik alanı ayrılamadı, sorum kullanarak olup olmadığıdır varchar(255)
daha verimli kullanılarak veya kıyasla daha fazla alan tasarrufu varchar(5000)
. Evet ise neden?
Yana varchar
zaten dinamik alanı ayrılamadı, sorum kullanarak olup olmadığıdır varchar(255)
daha verimli kullanılarak veya kıyasla daha fazla alan tasarrufu varchar(5000)
. Evet ise neden?
Yanıtlar:
Evet, tüm değerler ikincisine uyacağından varchar(5000)
daha kötü olabilir varchar(255)
. Bunun nedeni, SQL Server'ın veri boyutunu tahmin etmesi ve ardından bir tablodaki sütunların bildirilen ( gerçek olmayan ) boyutuna dayalı olarak bellek vermesidir . Sahip varchar(5000)
olduğunuzda, her değerin 2500 karakter uzunluğunda olduğunu varsayar ve buna göre bellek ayırır.
İşte son GroupBy sunumumun kötü alışkanlıklarla ilgili sunumunu kendim için kanıtlamayı kolaylaştıran bir demo (bazı sys.dm_exec_query_stats
çıktı sütunlarının SQL Server 2016 gerektirmesi gerekir, ancak yine de SET STATISTICS TIME ON
önceki sürümlerdeki diğer araçlarla kanıtlanmalıdır ); aynı verilere karşı aynı sorgu için daha büyük bellek ve daha uzun çalışma süreleri gösterir - tek fark sütunların belirtilen boyutudur:
-- 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];
Yani, evet, sütunlarınızı doğru boyutlandırın , lütfen.
Ayrıca, testleri varchar (32), varchar (255), varchar (5000), varchar (8000) ve varchar (maks) ile yeniden yaptım. Benzer sonuçlar ( büyütmek için tıklayın ), 32 ile 255 arasındaki ve 5.000 ile 8.000 arasındaki farklar önemsizdi:
İşte TOP (5000)
daha tam olarak tekrarlanabilen test için yapılan değişiklikle ilgili başka bir test: Sürekli olarak perişan oldum ( büyütmek için tıklayın ):
Dolayısıyla, 10.000 satır yerine 5.000 satır bile olsa (ve en azından SQL Server 2008 R2'ye kadar geriye doğru sys.all_columns'ta 5.000+ satır var), nispeten doğrusal bir ilerleme gözlenir - aynı verilerde bile, tanımlanan boyut büyüdükçe sütununda, aynı sorgunun yerine getirilmesi için daha fazla bellek ve zaman gerekir (anlamsız olsa bile DISTINCT
).
varchar(450)
ve varchar(255)
aynı olacak? (Ya da 4000'in altındaki bir şey?)
rowcount*(column_size/2)
.