Wäre die Verwendung von varchar (5000) im Vergleich zu varchar (255) schlecht?


27

Da varcharder 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


Benötigen Sie eine 5000 Zeichen breite Spalte? Wenn ja warum? Wäre eine varchar (MAX) -Spalte hier besser für Sie?
Richard L. Dawson

Antworten:


51

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_statsAusgabespalten, sollte aber mit SET STATISTICS TIME ONoder 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:

Bildbeschreibung hier eingeben

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 ):

Bildbeschreibung hier eingeben

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).


Das ist wirklich überraschend. Wäre der Unterschied zwischen varchar(450)und varchar(255)der gleiche? (Oder irgendetwas unter 4000?)
a_horse_with_no_name

@a_horse_with_no_name Ich habe nicht alle Permutationen der Laufzeitleistung getestet, aber die Speicherzuweisung wäre ein linearer Verlauf - es ist einfach eine Funktion von rowcount*(column_size/2).
Aaron Bertrand

Das ist dann ziemlich enttäuschend. Ich denke, dass moderne Versionen von SQL Server nicht darunter leiden (solange die definierte Länge kleiner als 8000 oder vielleicht 4000 ist).
a_horse_with_no_name

1
@a_horse_with_no_name Nun, es muss erraten werden, wie breit die Daten sind, damit keine Daten verschüttet werden. Wie sollte es sonst raten? Es kann nicht die gesamte Tabelle durchsuchen und lesen, um die durchschnittlichen / maximalen Längen aller Spalten mit variabler Breite als Vorläufer für die Erstellung eines Ausführungsplans zu bestimmen (und selbst wenn dies möglich wäre, wäre dies nur während einer Neukompilierung möglich).
Aaron Bertrand

2
Oracle führt Statistiken über z. B. die durchschnittliche Zeilenlänge, die Min- und Max-Werte für jede Spalte sowie ein Histogramm. Postgres führt sehr ähnliche Statistiken (es werden jedoch keine Min / Max-Werte, sondern Frequenzen aufgezeichnet). Für keines von beiden gibt es einen Unterschied zwischen nvarchar (150), nvarchar (2000) oder varchar (400) in der Leistung.
a_horse_with_no_name
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.