varchar (255)에 비해 varchar (5000)를 사용하는 것이 좋지 않습니까?


27

varchar어쨌든 공간을 동적으로 할당 하기 때문에 내 질문은을 사용하는 varchar(255)것보다 사용하는 것이 더 효율적인지 또는 더 많은 공간을 절약 하는지 varchar(5000)입니다. 그렇다면 왜 그렇습니까?


5000 자 너비의 열이 필요합니까? 그렇다면 왜? 여기에서 varchar (MAX) 열이 더 잘 작동합니까?
Richard L. Dawson

답변:


51

예, 모든 값이 후자에 맞는 경우 varchar(5000)보다 더 나쁠 수 있습니다 varchar(255). 그 이유는 SQL Server가 테이블에서 열의 선언 된 ( 실제 아님) 크기를 기준으로 데이터 크기와 메모리 부여를 추정하기 때문입니다 . 이 있으면 varchar(5000)모든 값의 길이가 2,500 자라고 가정하고이를 기반으로 메모리를 예약합니다.

다음은 최근의 GroupBy 프레젠테이션을 통해 나쁜 습관에 대한 데모를 보여줍니다. 일부 sys.dm_exec_query_stats출력 열에 는 SQL Server 2016이 필요 하지만 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 사이, 5,000에서 8,000 사이의 차이는 무시할 수 있지만 비슷한 결과 ( 확대하려면 클릭 )

여기에 이미지 설명을 입력하십시오

여기 TOP (5000)에 끊임없이 반복되는 더 완전 재현 가능한 테스트에 대한 변경 사항이있는 또 다른 테스트가 있습니다 ( 확대하려면 클릭하십시오 ).

여기에 이미지 설명을 입력하십시오

따라서 10,000 개 행이 아닌 5,000 개 행 (및 SQL Server 2008 R2와 먼 거리에서 sys.all_columns에 5,000 개 이상의 행이 있음)에도 동일한 데이터를 사용하더라도 정의 된 크기 가 클수록 상대적으로 선형적인 진행이 관찰 됩니다. 열의 값이 크면 정확히 동일한 쿼리를 충족시키는 데 더 많은 메모리와 시간이 필요합니다 (무의미한 경우에도 DISTINCT).


정말 놀랍습니다. 차이시겠습니까 varchar(450)varchar(255)동일? (또는 4000 이하의 무엇입니까?)
a_horse_with_no_name

@a_horse_with_no_name 런타임 성능의 모든 순열을 테스트하지는 않았지만 메모리 부여는 선형 진행이 될 것입니다 rowcount*(column_size/2). 단순히의 함수입니다 .
Aaron Bertrand

그때는 꽤 실망 스럽습니다. 비록 최신 버전의 SQL Server는 정의 된 길이가 8000 또는 4000보다 작은 한 그 문제를 겪지 않습니다.
a_horse_with_no_name

1
@a_horse_with_no_name 글쎄, 유출을 피하기 위해 데이터의 너비를 추측해야합니다. 어떻게 추측해야합니까? 실행 테이블 생성의 전조로 모든 가변 폭 열의 평균 / 최대 길이를 결정하기 위해 전체 테이블을 스캔하고 읽을 수 없습니다 (가능한 경우에도 재 컴파일하는 동안 만 수행 할 수 있음).
Aaron Bertrand

2
오라클은 히스토그램뿐만 아니라 각 행의 평균 행 길이, 최소값 및 최대 값에 대한 통계를 유지합니다. Postgres는 매우 유사한 통계를 유지합니다 (빈도는 아니지만 최소 / 최대는 기록하지 않습니다). 둘 중 어느 것도 nvarchar (150), nvarchar (2000) 또는 varchar (400)의 성능 차이가 없습니다.
a_horse_with_no_name
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.