DB

[MSSQL] VARCHAR(MAX|N) 길이별 성능차이 및 NVARCHAR와의 성능차이에 관해..

지과쌤 2022. 2. 8.
반응형

목차

    시작하며

    VARCHAR나 NVARCHAR를 선언할 때, 우리는 종종 해당 컬럼의 길이를 어떻게 놓을것인지에 대해서 고민하곤 한다.

     

    확실하게 정해져있는 경우, 고정길이로 선언해주는것이 성능상 더 좋다는것은 자명하지만, 그렇지 않은 경우 갈피를 잡기 어려울 수도 있다.

     

    VARCHAR(N) 컬럼에 데이터를 저장할땐, 물리적으로 같은 방식이 사용되며 저장된다. 이 말은, 어떤 특정한 동작 없이 블록에 바로 쓰인다는것이다.

     

    하지만, VARCHAR(MAX) 컬럼에 저장하는 경우, TEXT타입처럼 다뤄지게되어 저장을 위한 추가적인 절차가 필요하게된다. (단, 저장되는 데이터의 길이가 8000바이트 이상인 경우에만 해당된다.)

     

    8000바이트 이상인 경우, 오버플로우가 발생하게 되는데 이를 out of row 라고 한다.

    이때, 이 데이터를 저장하기 위해선 포인터가 사용되는데, 별개의 공간에 데이터를 저장하고 난 후, 이 공간을 가르키는 포인터(주소값)을 저장하게된다.

     

    SQL Server는 먼저 in row 방식으로 데이터를 저장하려고 시도한 후, 8000바이트를 초과하게되면 out of row 방식으로 저장하게 된다.

    https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms189087(v=sql.105) 

     

    In-Row Data

    Small-to-medium large value types (varchar(max), nvarchar(max), varbinary(max), and xml) and large object (LOB) data types (text, ntext, and image) can be stored in a data row. This behavior is controlled by using two options in the sp_tableoption system s

    docs.microsoft.com

    https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms186981(v=sql.105) 

     

    Row-Overflow Data Exceeding 8 KB

    A table can contain a maximum of 8,060 bytes per row. In SQL Server 2008, this restriction is relaxed for tables that contain varchar, nvarchar, varbinary, sql_variant, or CLR user-defined type columns. The length of each one of these columns must still fa

    docs.microsoft.com

     

    또한 해당 컬럼엔 인덱스를 생성할 수 없다.

     

    VARCHAR(N) vs VARCHAR(MAX) 성능 테스트

    SET NOCOUNT ON;
    
    
    
    --===== VARCHAR(10) 타입으로 100만건을 출력하는 테스트
    
    DECLARE @SomeString VARCHAR(10),
    
            @StartTime DATETIME;
    
    --=====         
    
     SELECT @startTime = GETDATE();
    
     SELECT TOP 1000000
    
            @SomeString = 'ABC'
    
       FROM master.sys.all_columns ac1,
    
            master.sys.all_columns ac2;
    
     SELECT testSize='10', Duration = DATEDIFF(ms,@StartTime,GETDATE());
    
    GO
    
    --===== VARCHAR(4000) 타입으로 100만건을 출력하는 테스트
    
    DECLARE @SomeString VARCHAR(4000),
    
            @StartTime DATETIME;
    
     SELECT @startTime = GETDATE();
    
     SELECT TOP 1000000
    
            @SomeString = 'ABC'
    
       FROM master.sys.all_columns ac1,
    
            master.sys.all_columns ac2;
    
     SELECT testSize='4000', Duration = DATEDIFF(ms,@StartTime,GETDATE());
    
    GO
    
    --===== VARCHAR(MAX) 타입으로 100만건을 출력하는 테스트
    
    DECLARE @SomeString VARCHAR(MAX),
    
            @StartTime DATETIME;
    
     SELECT @startTime = GETDATE();
    
     SELECT TOP 1000000
    
            @SomeString = 'ABC'
    
       FROM master.sys.all_columns ac1,
    
            master.sys.all_columns ac2;
    
     SELECT testSize='MAX', Duration = DATEDIFF(ms,@StartTime,GETDATE());
    
    GO

    위 쿼리는 VARCHAR(10), VARCHAR(4000), VARCHAR(MAX)를 100만건씩 루프하는 쿼리이다.

    어떻게 되는지 확인해보자.

    VARCHAR - 성능체크

    확실히 VARCHAR(MAX)는 느린것을 알 수 있다.

    번외로, NVARCHAR도 확인해보자.

    NVARCHAR - 성능체크

    당연한 사실이지만 좀더 느리다.

    결론

    컬럼의 속성을 구성할때, 해당 컬럼에 어떤 데이터가 들어올지 명확하게 계획을 수립하여 설계하는것이 좋겠다.

    모든 데이터베이스가 MAX 옵션을 지원할지도 미지수고, 특정 길이가 넘어가는 경우 따로 컨트롤을 할 수 있을지도 미지수이다. 물론 성능상의 문제도 있을것이고...

     

    아무튼, 조금 귀찮아도 확실하게 하고 가는것이 좋아보인다.

    반응형

    댓글

    💲 추천 글