Так как в varchar
любом случае динамически выделяется пространство, мой вопрос заключается в том, varchar(255)
будет ли использование более эффективным или сэкономит больше места по сравнению с использованием varchar(5000)
. Если да, то почему?
Так как в varchar
любом случае динамически выделяется пространство, мой вопрос заключается в том, varchar(255)
будет ли использование более эффективным или сэкономит больше места по сравнению с использованием varchar(5000)
. Если да, то почему?
Ответы:
Да, varchar(5000)
может быть хуже, чем varchar(255)
если бы все значения вписывались в последние. Причина в том, что SQL Server будет оценивать размер данных и, в свою очередь, предоставление памяти на основе объявленного (не фактического ) размера столбцов в таблице. Если у вас есть varchar(5000)
, он будет предполагать, что каждое значение имеет длину 2500 символов, и резервировать память на основе этого.
Вот демонстрация из моей недавней презентации GroupBy о вредных привычках, которая позволяет легко доказать это для себя (требуется SQL Server 2016 для некоторых sys.dm_exec_query_stats
выходных столбцов, но он все же должен быть подтвержден с помощью SET STATISTICS TIME ON
других инструментов в более ранних версиях); он показывает больший объем памяти и более длительное время выполнения для одного и того же запроса к тем же данным - единственное отличие заключается в объявленном размере столбцов:
-- 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];
Так что, да , пожалуйста, измените размер столбцов .
Кроме того, я перезапустил тесты с varchar (32), varchar (255), varchar (5000), varchar (8000) и varchar (max). Аналогичные результаты ( нажмите, чтобы увеличить ), хотя различия между 32 и 255 и между 5000 и 8000, были незначительными:
Вот еще один тест с TOP (5000)
изменением более полностью воспроизводимого теста, о котором меня постоянно преследовали ( нажмите, чтобы увеличить ):
Таким образом, даже с 5000 строк вместо 10000 строк (и в sys.all_columns более 5000 строк, по крайней мере, так же далеко, как в SQL Server 2008 R2), наблюдается относительно линейная прогрессия - даже с теми же данными, чем больше определенный размер столбца, тем больше памяти и времени требуется для выполнения точно такого же запроса (даже если он имеет бессмысленный смысл DISTINCT
).
varchar(450)
и varchar(255)
быть одинаковой? (Или что-нибудь ниже 4000?)
rowcount*(column_size/2)
.