Puisque de varchar
toute façon allouer de l'espace de manière dynamique, ma question est de savoir si l'utilisation varchar(255)
est plus efficace ou économise plus d'espace que l'utilisation varchar(5000)
. Si oui, pourquoi?
Puisque de varchar
toute façon allouer de l'espace de manière dynamique, ma question est de savoir si l'utilisation varchar(255)
est plus efficace ou économise plus d'espace que l'utilisation varchar(5000)
. Si oui, pourquoi?
Réponses:
Oui, cela varchar(5000)
peut être pire que varchar(255)
si toutes les valeurs rentrent dans ce dernier. La raison en est que SQL Server estimera la taille des données et, à son tour, les allocations de mémoire en fonction de la taille déclarée (non réelle ) des colonnes d'une table. Lorsque vous l'avez varchar(5000)
, il supposera que chaque valeur comporte 2 500 caractères et réservera de la mémoire en fonction de cela.
Voici une démo de ma récente présentation GroupBy sur les mauvaises habitudes qui facilite la preuve par vous-même (nécessite SQL Server 2016 pour certaines des sys.dm_exec_query_stats
colonnes de sortie, mais devrait toujours être prouvable avec SET STATISTICS TIME ON
ou d'autres outils sur les versions antérieures); il montre une plus grande mémoire et des durées d'exécution plus longues pour la même requête par rapport aux mêmes données - la seule différence est la taille déclarée des colonnes:
-- 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];
Alors, oui, dimensionnez correctement vos colonnes , s'il vous plaît.
De plus, j'ai relancé les tests avec varchar (32), varchar (255), varchar (5000), varchar (8000) et varchar (max). Des résultats similaires ( cliquez pour agrandir ), bien que les différences entre 32 et 255, et entre 5 000 et 8 000, étaient négligeables:
Voici un autre test avec le TOP (5000)
changement pour le test plus entièrement reproductible qui me harcelait sans cesse ( cliquez pour agrandir ):
Ainsi, même avec 5000 lignes au lieu de 10000 lignes (et il y a plus de 5000 lignes dans sys.all_columns au moins aussi loin que SQL Server 2008 R2), une progression relativement linéaire est observée - même avec les mêmes données, plus la taille définie est grande de la colonne, plus de mémoire et de temps sont nécessaires pour satisfaire exactement la même requête (même si elle n'a pas de sens DISTINCT
).
varchar(450)
et varchar(255)
serait-elle la même? (Ou quelque chose en dessous de 4000?)
rowcount*(column_size/2)
.