출처 : http://sisseo.tistory.com/8




오늘 얘기할 부분은 복합 인덱스 설정 시 발생할 수 있는 성능 차이에 대해서 말해 보겠습니다.

가끔 Primary Key 또는 인덱스 설정 시에 하나의 컬럼이 아닌 다수 컬럼을 묶어 인덱스를 설정하는 경우가 있습니다.

이때 컬럼 순서에 따라 의도하지 않게 성능 저하가 일어날 수 있습니다.

 

예를 들어 설명해 보죠.

col1, col2, col3 이라는 컬럼이 존재하고 3개의 컬럼이 PK로 잡혀야 하는 비즈니스 입니다.

 

처음으로 할 테스트는 컬럼 순서대로 인덱스를 설정한 경우입니다.


--테이블생성

CREATE TABLE dbo.PKDesign_Test (

        col1 INT  not null,

        col2 INT IDENTITY(1, 10) not null,

        col3 CHAR(3) not null )

--컬럼순서대로PK 설정 

ALTER TABLE dbo.PKDesign_Test ADD  CONSTRAINT [PK_PKDesign_Test] PRIMARY KEY CLUSTERED

(

        col1, col2, col3 ASC

)

--테스트데이터넣기

DECLARE @i INT = 1

WHILE @i < 1000       

        BEGIN

                   INSERT INTO dbo.PKDesign_Test(col1, col3)

                   SELECT @i, REPLICATE(LEFT(NEWID(), 1), 3)

                   SET @i = @i + 1

        END

 

그런데 아래와 같이 해당 테이블을 조회할 때 사용되는 필터링 컬럼은 col2, col3라고 하는군요.

SELECT col1, col2, col3

FROM dbo.PKDesign_Test

WHERE col2 > 5000 and col3 = 'EEE'






위 실행계획에서 보시는 것과 같이 복합 인덱스 첫 번째 컬럼이 필터조건에 존재하지 않으면,

Index Scan  Full Scan이 일어나 인덱스를 사용할 수 없습니다.

결국 인덱스를 설정했지만 사용하지도 못하는 인덱스가 돼버렸네요.

그렇기 때문에 인덱스 설정 시 필터 대상 컬럼은 반드시 첫 번째 위치에 존재해야 합니다.

 

아마 이건 다 아시는 내용일 수도 있겠네요.

사실 제가 말하고자 한 내용은 이제부터 입니다.

Col2, col3를 필터조건으로 걸 때에도 두 컬럼의 순서에 따라 성능 차이가 있을 수 있습니다.

 

그럼 col2 컬럼이 첫 번째인 인덱스와 col3 컬럼이 첫 번째인 인덱스를 갖는 테이블을 각각 생성해 보겠습니다.


CREATE TABLE dbo.PKDesign_Test1 (

        col1 INT  not null,

        col2 INT IDENTITY(1, 10) not null,

        col3 CHAR(3) not null );

--col2 컬럼이첫번째     

ALTER TABLE dbo.PKDesign_Test1 ADD  CONSTRAINT [PK_PKDesign_Test1] PRIMARY KEY NONCLUSTERED

(

        col2, col3, col1 ASC

);

 

CREATE TABLE dbo.PKDesign_Test2 (

        col1 INT  not null,

        col2 INT IDENTITY(1, 10) not null,

        col3 CHAR(3) not null );

--col3 컬럼이첫번째     

ALTER TABLE dbo.PKDesign_Test2 ADD  CONSTRAINT [PK_PKDesign_Test2] PRIMARY KEY NONCLUSTERED


(

        col3, col2, col1 ASC

);

 

--dbo.PKDesign_Test 테이블에서데이터복사

INSERT INTO dbo.PKDesign_Test1(col1, col3)

SELECT col1, col3

FROM dbo.PKDesign_Test;

 

INSERT INTO dbo.PKDesign_Test2(col1, col3)

SELECT col1, col3

FROM dbo.PKDesign_Test;

 

테이블 생성과 동일한 데이터를 두 테이블에 입력하였습니다.

그럼아래와 같이 각각의 테이블에 동일한 쿼리를 만들어 실행계획을 살펴 볼까요?

SELECT col1, col2, col3

FROM dbo.PKDesign_Test1

WHERE col2 > 5000 and col3 = 'EEE'

 

SELECT col1, col2, col3

FROM dbo.PKDesign_Test2

WHERE col2 > 5000 and col3 = 'EEE'







위 실행계획을 보면 필터 조건에 복합 인덱스 첫 번째 행이 포함되어 있기 때문에

두 쿼리 모두 Index Seek(인덱스에서 행 검색)을 확인하실 수 있습니다.

 

다만쿼리 비용은 58% 42%로 차이가 발생합니다.

실행계획을 자세히 보도록 하겠습니다.


            [PKDesign_Test1] 테이블       

        



           [PKDesign_Test2] 테이블




보시면 아시겠지만 Test1 테이블(col2 첫번째 컬럼)은 인덱스 검색을 col2 > 5000 보단 큰 값을

검색하면서 col3 = EEE’ 인 Row을 찾아 냅니다.

이 와는 다르게 Test2 테이블(col3 첫번째 컬럼)은 인덱스 검색을 col3 = EEE’ 인 값을 우선 찾고

그 중에 col2 > 5000  Row를 찾아 냅니다.

 

어떤 게 더 유리할까요?

Col2 > 5000  rows 499개 이며, col3 = EEE’ 인 rows 63개 입니다.(실제 테이블이 더 크다면 차이도 더 클 겁니다.)

당연히 비교적 낮은 row 수를 갖는 col3 컬럼을 먼저 찾아 내는 게 유리합니다.

 

보통 범위연산(부등호보다 ‘=’ 연산이 좁은 범위의 rows을 갖기 때문에

복합 인덱스 설정 시에는 컬럼 순서 조정을 고려해서 디자인하는 것이

성능에 매우 유리합니다.

 


~



Posted by motolies
,