Da varchar
der Speicherplatz sowieso dynamisch zugewiesen wird, ist meine Frage, ob die Verwendung varchar(255)
effizienter ist oder mehr Speicherplatz spart als die Verwendung varchar(5000)
. Wenn ja warum
Da varchar
der Speicherplatz sowieso dynamisch zugewiesen wird, ist meine Frage, ob die Verwendung varchar(255)
effizienter ist oder mehr Speicherplatz spart als die Verwendung varchar(5000)
. Wenn ja warum
Antworten:
Ja, varchar(5000)
kann schlimmer sein, als varchar(255)
wenn alle Werte in letzteren passen. Der Grund dafür ist, dass SQL Server die Datengröße und im Gegenzug die Speicherzuweisungen basierend auf der deklarierten (nicht tatsächlichen ) Größe der Spalten in einer Tabelle schätzt . Wenn dies der Fall ist varchar(5000)
, wird davon ausgegangen, dass jeder Wert 2.500 Zeichen lang ist, und der darauf basierende Speicher wird reserviert.
Hier ist eine Demo von meiner kürzlichen GroupBy-Präsentation zu schlechten Gewohnheiten , die es einfach macht, sich selbst zu beweisen (erfordert SQL Server 2016 für einige der sys.dm_exec_query_stats
Ausgabespalten, sollte aber mit SET STATISTICS TIME ON
oder anderen Tools in früheren Versionen noch beweisbar sein ). Es zeigt mehr Speicher und längere Laufzeiten für die gleiche Abfrage für die gleichen Daten - der einzige Unterschied ist die angegebene Größe der Spalten:
-- 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];
Also, ja , bitte passen Sie die Größe Ihrer Spalten an .
Außerdem habe ich die Tests mit varchar (32), varchar (255), varchar (5000), varchar (8000) und varchar (max) wiederholt. Ähnliche Ergebnisse ( zum Vergrößern anklicken ), obwohl die Unterschiede zwischen 32 und 255 und zwischen 5.000 und 8.000 vernachlässigbar waren:
Hier ist ein weiterer Test mit der TOP (5000)
Änderung für den vollständig reproduzierbaren Test, über den ich unaufhörlich schlecht gelaunt wurde ( zum Vergrößern klicken ):
Selbst mit 5.000 Zeilen anstelle von 10.000 Zeilen (und in sys.all_columns sind mindestens 5.000 Zeilen älter als SQL Server 2008 R2) wird ein relativ linearer Verlauf beobachtet - selbst bei denselben Daten ist die definierte Größe umso größer Je mehr Speicher und Zeit in der Spalte erforderlich sind, um genau die gleiche Abfrage zu erfüllen (auch wenn eine sinnlose Abfrage vorliegt DISTINCT
).
varchar(450)
und varchar(255)
der gleiche? (Oder irgendetwas unter 4000?)
rowcount*(column_size/2)
.