1. 사전구성
CREATE TABLE TB_ORFirst (seq INT, date DATETIME);
CREATE TABLE TB_ORSecond (seq INT, gid INT, txt NVARCHAR(36) DEFAULT (NEWID() ) );
INSERT INTO TB_ORFirst
SELECT ROW_NUMBER() OVER (ORDER BY a.number) seq
, DATEADD(d, a.number, '2020-01-01') date
FROM master..spt_values a (NOLOCK)
, (SELECT number
FROM master..spt_values (NOLOCK)
WHERE type = 'P' AND number <20) b
WHERE type = 'P'
AND a.number <= 365
;
INSERT INTO TB_ORSecond
SELECT b.seq, a.number, NEWID()
FROM master..spt_values a (NOLOCK), TB_ORFirst b
WHERE type = 'P'
AND number%2 = 1
AND number <= 100
;
CREATE CLUSTERED INDEX CIDX01_ORFirst ON TB_ORFirst (date);
CREATE INDEX NIDX01_ORSecond ON TB_ORSecond (seq, gid) INCLUDE (txt);
table_name |
index_name |
index_description |
Is_Unique |
indexed_columns |
included_columns |
TB_ORFirst |
CIDX01_ORFirst |
clustered |
0 |
date |
[NULL] |
TB_ORSecond |
NIDX01_ORSecond |
nonclustered |
0 |
seq, gid |
txt |
2. AS-IS
SELECT f.date, s.txt
FROM TB_ORFirst f
INNER JOIN TB_ORSecond s
ON f.seq = s.seq
WHERE f.date BETWEEN '2020-01-01' AND '2020-02-28'
AND s.gid IN (1,2,3,7,8,9,13,14,15,19,20,21,25,26,27,31,32,33)
;
- 후행 테이블의 조인 조건과 IN 조건절 컬럼이 인덱스 키로 생성되어 있다. 인덱스로 탐색하는 횟수가 과다하게 많아 지는 현상이다.
- NL Join으로 인해 선행 테이블의 결과 집합 건수(1,180)만큼 후행 테이블을 참조하며 그 결과 집합은 1건당 IN 절의 조건 개수(18) 만큼 인덱스를 탐색하게 된다.
- 테이블 검색 수 = 선행 테이블 데이터 건수 * IN 조건절 개수 = 1,180 * 18 = 21,240
3. TO_BE
// IN 조건절이 인덱스 탐색 조건의 대상이 되지 못 하도록 컬럼을 고의적으로 가공.
SELECT f.date, s.txt
FROM TB_ORFirst f
INNER JOIN TB_ORSecond s
ON f.seq = s.seq
WHERE f.date BETWEEN '2020-01-01' AND '2020-02-28'
AND s.gid + 0 IN (1,2,3,7,8,9,13,14,15,19,20,21,25,26,27,31,32,33)
;
// Hash Join으로 유도하여 테이블 검색 수를 최소화
CREATE INDEX NIDX02_ORSecond ON TB_ORSecond (gid) INCLUDE (seq, txt)
;
SELECT f.date, s.txt
FROM TB_ORFirst f
INNER JOIN TB_ORSecond s
ON f.seq = s.seq
WHERE f.date BETWEEN '2020-01-01' AND '2020-02-28'
AND s.gid IN (1,2,3,7,8,9,13,14,15,19,20,21,25,26,27,31,32,33)
OPTION (HASH JOIN )
;
- IN 조건절이 인덱스 탐색 조건의 대상이 되지 못 하도록 컬럼을 고의적으로 가공한다.
- Hash Join으로 유도하여 테이블 검색 수를 최소화한다.
- 조인 조건을 제외한 조건절 컬럼을 키로 생성하여 Hash Join으로 유도한다.
- IN 절의 조건절 개수 만큼만 인덱스로 탐색을 수행하기 때문에 검색 횟수가 감소된다.
- 조건절을 탐색하는 스캔 범위에 따라 I/O가 결정된다.
댓글