SlideShare a Scribd company logo
1 of 49
Download to read offline
SQL Server Access Patterns
Sungwook Kang
Speaker
강성욱 (Sungwook Kang)
LA 한인 IT 커뮤니티
http://sqlangeles.com
Data Platform
2012 ~ Present
http://sqlmvp.kr
SQLMVP
Sungwook Kang
/sqlmvp
Sungwook Kang
/sqlmvp-sungwookkang
Agenda
• Data Structure
• Index
• Access Patterns
How to be good at tuning
Understand your business
• 매일 오후에 실행되는 배치 작업이 있다면?
• 반드시 오후에 필요한 작업인가?
• 프로덕션 서버에서 해야만 하는가?
Tuning for top slow query (Cost of total resource)
• 어느것이 더 효율적인가?
• 100Page I/O Vs 10000Page I/O?
ü 100Page : 초당 10000호출
ü 10000Page : 초당 1번 호출
Understand Optimizer
• 사람이 생각하는 방식이 아닌 옵티마이저 관점에서 생각
• 비즈니스를 이해한 다음 옵티마이저에게 올바른 길을 제시한다.
Table and Index
• Table
• Page Type
• Data Page Structure
• Extents
• Index
ü Clustered Index
ü Non-Clustered Index
• Index Depth for Performance
• Composite Key
Table
• 테이블은 하나 이상의 파티션에 포함
• 힙(Heap), 클러스터(Clustered) 인덱스 구조
• 인덱스 페이지는 데이터 행의 열 유형에 따라 하나 이상의 할당 단위로 관리
Data Page Structure
• Page는 SQL Server에서 기본 저장 단위
• 1Page = 8K (1M = 128Page)
• Page Header 부분에서 96Byte의 시스템 정보 저장
• ROW Offsets 부분에서 36Byte의 오프셋 정보 저장
실제 데이터는 8060Byte
8060Byte 초과하는 데이터는 ROW_OVERFLOW_DATA 영역에
저장되고 원래 페이지에는 24Byte의 포인터 정보만 저장
• 페이지 끝에서부터 2Byte씩 배열 형태로 저장
• 행의 논리적 순서를 나타냄
• 정렬이 필요한 경우 행 오프셋 배열로 관리
• PageID : 현재 페이지 주소
• nextPage : 다음 페이지 주소
• prevPage : 이전 페이지 주소
• LSN : 현재 페이지의 변경 로그 시퀀스
• SlotCnt : 현재 페이지의 행 수
• Level : 인덱스 레벨 (0인경우 리프)
• IndexId : 페이지의 인덱스 ID (데이터 페이지의 경우 0)
Extents
• 논리적으로 연속된 8개의 Page 묶음 (64KB)
• Mixed Extents (익스텐트에 서로 다른 개체가 섞여 있음)
• Uniform Extents (익스텐트에 하나의 개체만 포함)
• 테이블이나 인덱스가 생성되면
ü 우선 Mixed Extents에 할당
ü 8페이지 이상 증가시 Uniform Extents에 할당
• 익스텐트 할당 정보는 IAM에서 관리
• 하나의 IAM은 64000 extents 페이지 또는 4GB까지 파일
범위를 처리
• Double linked list구조
Page Type
Page Type Comments
Data 큰 데이터 형식을 제외한 모든 데이터가 저장
Index 인덱스 데이터 저장
Text/Image
큰 데이터 형식과 8KB를 초과하는 가변 데이터 형식 저장
text, ntext, image, nvarcar(max), varchar(amx), varbinary(max), xml 등
GAM
(Global Allocation Map)
익스텐트 할당 여부 기록 (1:익스텐트 비어있음, 0 : 익스텐트 할당되어 있음)
SGAM
(Shared GAM)
혼합 익스텐트
• 1 : 혼합 익스텐트이며 빈 페이지가 존재
• 0 : 혼합 익스텐트가 아니거나 혼합익스텐트 이지만 여유 페이지가 없음
PFS
(Page Free Space)
페이지 할당 상태를 기록
IAM
(Index Allocation Map)
테이블 또는 인덱스 등의 개체가 할당된 익스텐트에 대한 정보
BCM
(Bulk Change Map)
마지막 Backup log 수행 후 대량 로그 작업에 의해 수정된 익스텐트 정보
DCM
(Differential Changed Map)
마지막 Backup Database 수행 후 변경된 익스텐트 정보 (1: 마지막 백업 후 변경, 0 : 마지막 백업 후 변경없음)
Index
TABLE
Heap Clustered Index
• 클러스터 인덱스가 없음
• 페이지 연결을 고려하지 않음
• 정렬을 고려하지 않음
• 데이터 검색 시 전체 스캔 발생
• 클러스터 인덱스를 생성
• 데이터가 B-Tree 형태로 구조로 저장
Clustered Index
• 인덱스 키 값을 기반으로 테이블 데이터 행 전체를 정렬해서 저장
• B-Tree 구조
• 리프 레벨에만 데이터 전체가 저장
• 루트와 넌리프 인덱스 페이지에는 인덱스 키 값과 6Byte의 페이지 참조값 (2Byte FileID + 4Byte PageID)만 저장
• 고유 컬럼이면 UNIQUE 인덱스로 생성할 것 권장
ü UNIQUE로 설정되어 있지 않으면 고유한 주소값을 만들기 위해 4Byte의 uniquefier 정보를 추가로 저장
• 키 값으로 정렬된 넓은 범위 검색에 유리
• 테이블당 1개 인덱스 생성 가능
Non-Clustered Index
• 테이블과 별개로 인덱스 키로만 구성된 별도의 B-Tree 인덱스 영역 생성
• 고유 컬럼이면 UNIQUE 인덱스로 생성할 것 권장
ü UNIQUE로 설정되어 있지 않으면 고유한 주소값을 만들기 위해 4Byte의 uniquefier 정보를 추가로 저장
• 테이블 구조에 따라 인덱스 구조가 조금 다름
ü Heap에서 Non-Clustered 인덱스 생성
ü Clustered 인덱스가 있는 상태에서 Non-Clustered 인덱스 생성
• 테이블에 여러 개의 인덱스 생성 가능 (SQL Server 2008 later : 999개)
Non-Clustered Index
Non-Clustered Index (Heap) Non-Clustered Index (Clustered)
• 인덱스 페이지에는 각 행마다 키 값과 행의
위치값인 8Byte RID (FileID : 2Byte, PageID : 4Byte,
SlotNumber : 2Byte)가 인덱스 키로 정렬되어 저장
• RID 값으로 힙 영역에서 인덱스 레벨이 아닌
컬럼을 검색
• 인덱스 페이지에는 RID가 아닌 클러스터 인덱스
키 값 저장
• 클러스터 인덱스가 UNIQUE이면 uniquefier 값은
없음
Index Key size, Index depth and Performance
• 인덱스 페이지 크기는 8192Byte (데이터 페이지와 동일)
• 인덱스 깊이가 깊어 질 수록 성능에 영향을 받음
• 키의 크기가 작을 수록 한 페이지당 저장 데이터 많아져 검색 효율이 높음
• 인덱스 선정에 중요한 기준 (꼭 필요한 컬럼만 할 것)
900Byte key 20Byte key
1p (7row)
7p (22row)
22p (129row)
129p (983row)
983p (7818row)
7818p (62505row)
62505p (499999row)
1p (12row)
12p (2108row)
2108p (499999row)
Index Design – Composite Key
• 두 개 이상의 컬럼을 Key Column 으로 사용
• 선행 컬럼에 따라 성능 차이가 큼
ü 선행 컬럼으로 Seek 여부를 결정
WHERE OrderDate BETWEEN '2012-02-26' AND '2012-02-27’ AND OrderNum=7000
OrderDate OrderNum
… …
2013-02-26 1
… …
2013-02-26 7000
… …
2013-02-27 7000
… …
OrderNum OrderDate
… …
6998 2013-02-26
6999 2013-02-28
7000 2013-02-26
7000 2013-02-27
7002 2013-02-26
… …
Index Design – Composite Key
Index_name Index_description Index_keys
IX_Tindex_col3_col1 nonclustered located on PRIMARY col3, col1
IX_Tindex_col1_col3 nonclustered located on PRIMARY col1, col3
SELECT col3, col1 FROM dbo.THeap WITH(INDEX (IX_THeap_col3_col1))
WHERE col3 = 1 AND col1 = 5
SELECT col3, col1 FROM dbo.THeap WITH(INDEX (IX_THeap_col1_col3))
WHERE col1 = 5 AND col3 = 1
• col3 + col1과 col1 + col3 트리 높이가 동일하므로 검색 속도가 같다.
• 독립적인 col1, col3의 선택도는 다르지만 복합 인덱스col1 + col3, col3 + col1 선택도가 동일하므로 Equal(=)
검색에서는 선택도의 의미가 없으며 성능도 같다.
Scan count 1, logical reads 3, physical reads 0
Scan count 1, logical reads 3, physical reads 0
Access Type
• Sequential Access
• Random Access
• Scan
• Seek
• Lookup
• Covered Index
• Selectivity
Sequential Access
• 데이터를 정렬된 순서대로 차례대로 읽어가는 방식
• 데이터가 밀집되어 있어 다음에 읽을 데이터 위치가 예측 가능하다
• 모든 검색 비용 동일
ü 큰 범위 검색 유리
ü 포인트로 읽어야 할 때는 불필요한 데이터 까지 읽음
• 데이터가 많을 수록, 시작지점에서 멀어질 수록 성능이 떨어짐
1
2
4
5
7
8
9
10
11
12
13
14
1 9
1
Random Access
• 데이터의 할당 정보를 이용해서 읽는 방식
• 저장 위치와 상관없이 동일한 시간 소요
• 하나 또는 작은 범위 검색에 유리
ü 14를 검색하기 위해선 1번의 액세스 발생
ü 1~14까지 검색하기 위해선 14번 액세스 발생
A0 A4 A8 AC
A1 A5 A9 AD
A2 A6 AA AE
A3 A7 AB AF
Heap
1-A0
2-A1
4-A2
5-A3
7-A4
8-A5
9-A6
10-A7
11-A8
12-A9
13-AA
14-AB
1 9
1
Scan
• 테이블 전체 또는 인덱스의 리프 레벨을 모두 읽는 방식
• Scan 비용은 테이블의 행 수에 비례.
• 사이즈가 작은 테이블이나 검색 범위가 클 때 사용
1
2
4
5
7
8
9
10
11
12
13
14
1 9
1
할당 순서 Scan
• IAM에 저장되어 있는 익스텐트 할당 순서대로 읽음
• 정렬이나 인덱스 조각화로 인한 페이지 분할에 크게 영향 받지 않음
인덱스 정렬 Scan
• 인덱스 리프 첫 페이지부터 순서대로 읽음
• 페이지 분할이 많이 발생할 수록 성능이 느려짐
Seek
• 인덱스트리를 타고 하나의 값을 검색하는 방식
• 하나의 값을 검색하고 다른 값을 계속 읽는 것 (Seek + Range)
ü Operator를 Seek 로 표시
• Scan과 Seek는 데이터의 많고 적음이 아니라 액세스하는 방법의 정의에 따름
1
2
4
5
7
8
9
10
11
12
13
14
1 9
1
1
2
4
5
7
8
9
10
11
12
13
14
1 9
1
WHERE Idx in (5,12) WHERE Idx > 4
Lookup
• Non-Clustered 인덱스에서 인덱스 레벨에 저장되어 있지 않은 행을 검색하기 위해 인덱스 레벨의 주소 값으로
직접 Heap 또는 Clustered 인덱스 영역에서 검색
ü RID Lookup : Heap 영역에서 검색
ü Key Lookup : 인덱스 키를 이용한 검색
• Lookup은 인덱스 페이지의 주소값을 이용한 랜덤 액세스 방식으로 실제 I/O 비용이 많이 발생함
A0 A4 A8 AC
A1 A5 A9 AD
A2 A6 AA AE
A3 A7 AB AF
Heap
1-A0
2-A1
4-A2
5-A3
7-A4
8-A5
9-A6
10-A7
11-A8
12-A9
13-AA
14-AB
Covered Index
• 쿼리에 사용된 모든 컬럼이 인덱스로 구성되어 있는것 (인덱스 종류는 아님)
• 필요 컬럼을 인덱스 레벨에서 검색할 수 있어 Lookup 이 발생하지 않음.
Selectivity
• 전체 데이터 집합에서 특정 조건에 의해 필터링 되는 데이터 비율
• 비율이 낮을 수록 선택도가 높다.
• 데이터 검색시 옵티마이저가 인덱스를 결정하는 중요한 역할 담당
• 인덱스 선정 또는 쿼리 작성시 신경써야 하는 부분
SELECT
COUNT( DISTINCT ColName ) AS DistinctValues,
COUNT( ColName ) AS TotalNumberOfValues,
COUNT( DISTINCT ColName ) / COUNT( ColName ) * 100.0 AS Selectivity
FROM TableName;
Access Patterns Type
• Table Scan
• Cluster Index Scan
ü Cluster Index Scan – Ordered false
ü Cluster Index Scan – Ordered true
• Covered Index Scan
ü Covered Index Scan – Ordered false
ü Covered Index Scan – Ordered true
• Clustered Index Seek + Range Scan
• Covered Index Seek + Range Scan
• Non-Clustered Index Seek + Range Scan + Lookup
ü Non-Clustered Index Seek + Range Scan + Lookup (Heap)
ü Non-Clustered Index Seek + Range Scan + Lookup (Clustered)
• Non-Clustered Index Scan + Lookup (Heap)
• Non-Clustered Index Scan + Lookup (Clustered)
Table Scan
• Heap 구조 전체를 읽으며 IAM에서만 할당 정보를 알 수 있으므로 할당 순서 Scan 방식 사용
• 스캔이발생하는 조건
ü 소형 테이블 : 인덱스가 존재하여도 테이블이 작으면 스캔으로 작동
ü 적절한 인덱스가 없음 : 필터 조건이 인덱스에 없거나 복합 인덱스의 선행 컬럼이 검색 조건에 없음
ü 넓은 범위 액세스 : Lookup 비용이 너무 높으면 Full Scan 작동
SELECT * FROM dbo.tblx;
Clustered Index Scan
• 클러스터 인덱스 테이블에서 리프 레벨을 모두 읽는다.
• 정렬된 결과 값을 읽어야 하느냐에 따라 Scan 방식이 다르다.
• 정렬을 지정하지 않아도 정렬된 결과가 출력될 수도 아닐 수도 있다.
ü 스토리지 엔진의 Scan 방식은 사용자가 선택할 수 없다.
• 인덱스 키로 정렬해야 한다면 반드시 ORDER BY를 명시 한다.
• 정렬이나 데이터 일관성이 꼭 필요하지 않다면 격리 수준을 낮추어서 성능에 유리한 할당 Scan 방식을 유도한다.
Clustered Index Scan – Ordered false
SELECT * FROM dbo.TIndex
Index_name Index_description Index_keys
IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1
SELECT * FROM dbo.Tindex with (nolock);
SELECT * FROM dbo.Tindex with (tablock);
(데이터 순서는 사용자마다 다르게 출력될 수 있음)
Cluster Index Scan – Ordered false
• 스토리지 엔진이 Scan 방식을 선택할 때 성능 뿐만 아니라 데이터 일관성도 고려
• 정렬 여부 및 격리 수준을 낮추게 되면 할당 순서 Scan을 할 가능성 이 높다.
• 인덱스 정렬 스캔이 할당 순서 스캔보다 성능이 느리다.
• 인덱스 정렬 Scan 은 데이터가 많거나 인덱스 조각화가 많이 일어날 수록 성능이 느려진다.
SELECT * FROM dbo.TIndex
SELECT * FROM dbo.Tindex with(nolock);
SELECT * FROM dbo.Tindex with (tablock);
Cluster Index Scan – Ordered true
Index_name Index_description Index_keys
IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1
SELECT * FROM dbo.TIndex ORDER BY col3, col1;
Cluster Index Scan – Ordered ture
SELECT * FROM dbo.TIndex ORDER BY col3, col1;
• 옵티마이저가 정렬을 보장하기 위해 ordered 속성은 True로 표시
• 인데스 정렬 Scan 방식만 사용가능
Page split, IAM Scan and Index Scan performance
[Test Senario]
클러스터 인덱스 테이블에 논리적 조각화를 발생
• 할당 정렬 스캔과 인덱스 정렬 스캔 방식 비교
• 디스크로부터 읽었을 때와 메모리에서 읽을 때 비교
[Conclusion]
데이터가 메모리에 있지 않거나 테이블에서 정렬된 검색결과를 검색해야하는 경우가 아니라면
• ORDER BY를 생략하거나
• WITH (NOLOCK) 힌트를 이용해 격리수준을 최소화하여
• 할당 순서 스캔을 선택하도록 유도하는 것이 성능에 좋다.
Disk Memory
할당순서 Scan Index Scan 할당 순서 스캔 Index Scan
Flagmentation
Ratio (%)
99% 1436ms 16315ms 738ms 756ms
0% 879ms 916ms 745ms 754ms
Covered Index Scan
• 테이블 구조와 상관없이 비클러스터형 인덱스의 리프 페이지만 검색하는 패턴
• 비클러스터형 인덱스는 인데스 키 컬럼과 Include 컬럼만 저장되어 있어 인덱스 사이즈가 작아 scan 범위가
작다는거 외에는 클러스터형 인덱스 scan 과 동일
• 필요한 컬럼이 인덱스 레벨에 있어 Lookup 과정이 생략되어 쿼리 성능에 향상
Index_name Index_description Index_keys
IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1
IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
SELECT col2, col3, col5 FROM dbo.TIndex
SELECT col1, col2, col3, col5 FROM dbo.TIndex
• 일반적인 인데스 커버링 (col2를 include로 넣었으므로 인덱스 커버됨)
• Scan count 1, logical reads 3986, physical reads 0
• 비클러스터형 인덱스 + 클러스터형 인덱스
• Scan count 1, logical reads 3986, physical reads 0
Covered Index Scan
SELECT col2, col3, col5 FROM TIndex
Index_name Index_description Index_keys
IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1
IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
Covered Index Scan – Ordered false
• ORDER BY를 명시하지 않으면 정렬이 보장 되지 않음
• 스토리지 엔진은 할당 순서 스캔, 인덱스 정렬 스캔 방식을 선택할 수 있음
• 첫 번째 키가 아닌 정렬요소는 false로 표시되고 별도 sort 비용까지 추가됨
• 복합 인덱스에서는 키 순서 중요
SELECT col1, col2, col3, col5 FROM dbo.Tindex ORDER BY col5
Index_name Index_description Index_keys
IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1
IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
Covered Index Scan – Ordered true
• 복합 인덱스의 첫 번째 컬럼으로 정렬을 명시하거나, 집계 쿼리에서 Stream Aggregate 연산자로 실행 계획이
풀리면 우선 정렬을 해야 하므로 정렬속성이 True를 생성
• 집계 쿼리에서 대상 컬럼의 인덱스가 없어 Hach Match Aggregate 연산자로 풀리면 따로 해시 테이블을 만들기
때문에 정렬이 필요없어 Flase 를 생성
SELECT col1, col2, col3, col5 FROM dbo.Tindex ORDER BY col3
SELECT col3, col5, count(*) cnt FROM dbo.Tindex GROUP BY col3, col5
Index_name Index_description Index_keys
IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1
IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
Clustered Index Seek + Range Scan
• 클러스터 인덱스의 루트 레벨로부터 트리를 타고 검색한 뒤 데이터가 위치한 리프 레벨에서 범위 스캔
• 인덱스 Seek 후 리프 레벨을 순차적으로 Scan하기 때문에 인덱스 키 순서대로 정렬된 범위 검색에 유리
• 필터링 조건이 첫번째 키라면 처음 인덱스 Seek 후 필터링 조건이나 첫번째 키 컬럼의 분포도가 비용 결정
Covered Index Seek + Range Scan
• 첫번째 키 컬럼으로 인덱스 Seek한 다음 범위 Scan (클러스터 인덱스 Seek + Range Scan동일)
• Lookup 비용이 들지 않음
• 커버링된 컬럼만 포함하므로 모든 데이터를 포함하는 클러스터 인덱스 패턴보다 비용이 낮음
• 두 번째 필터 조건이나 분포도에 따라 비용이 달라짐
SELECT col1, col3 FROM dbo.Tindexrange WHERE col3 = 10
Non-Clustered Index Seek + Range Scan + Lookup
• 인덱스 Seek + Range Scan 하면서 인덱스 커버링이 되지 않은 컬럼을 검색하기 위해
ü 힙이나
ü 클러스터 인덱스를 Lookup
• 일반적으로 포인터 검색 이나 좁은 범위 검색에 적합
• 범위가 넓어질수록 Lookup이 많이 발생하여 랜덤 I/O 비용이 늘어난다
• 랜덤 I/O 비용이 너무 높다고 판단되면 옵티마이저는 테이블 또는 인덱스 Scan을 할 수 있다.
• 다음에 읽어야 할 데이터가 동일한 페이지에 있어도 동일 페이지를 다시 액세스 한다.
SELECT * FROM dbo.Theap WHERE col5 = '2012-01-01'AND col3 between 1 and 200
Non-Clustered Index Seek + Range Scan + Lookup (Heap)
• 쿼리에서 소요되는 비용은 비클러스터 인덱스 높이 + 검색된 로우수 (Lookup 횟수)
Non-Clustered Index Seek + Range Scan + Lookup (Clustered)
SELECT * FROM dbo.TIndex WHERE col5 = '2012-01-01' AND col3 between 1 and 200
• 쿼리에서 소요되는 비용은 비클러스터 인덱스 높이 + (검색된 로우수X클러스터 인덱스 높이)
Non-Clustered Index Scan + Lookup (Heap)
SELECT * FROM dbo.Theap WHERE col3 = 10
• 리프 레벨을 모두 스캔하고 리프 레벨 데이터 수 만큼 Lookup 한다
• 랜덤I/O 비용이 많이 발생하므로 테이블 스캔 또는 인덱스를 다시 디자인 하는것이 좋다
• 옵티마이저는 선택도가 충분해도 룩업 비용이 많이 발생하면 스캔할 수도 있다.
SELECT * FROM dbo.Tindex WHERE col1 BETWEEN 1 AND 100
Non-Clustered Index Scan + Lookup (Clustered)
Strategy for Access patterns
• I/O read performance each data selectivity
• Query performance for each selectivity
I/O read performance each data selectivity
I/O read performance each data selectivity
Query performance for each selectivity
• 좁은 범위 검색
ü Non-Clustered Index Seek + Range Scan + Lookup
ü Clustered Index Seek + Range Scan
ü Covered Index Seek + Range Scan
ü Lookup 패턴은 어느 순간부터 비용이 급격히 늘어나기
때문에 포인트 쿼리 또는 아주 작은 범위 검색에만 사용
• 중간 이상의 범위 검색
ü Covered Index Seek + Range Scan
ü Clustered Index Seek + Range Scan
ü 이 두 패턴은 선택도에 따라 선형으로 비용이 증가
ü 인덱스 키로 정렬된 결과를 보장하고 필요한 만큼 부분
스캔을 수행하므로 정렬된 범위 검색시 가장 이상적
ü 선택도가 높아질수록 부분 범위 스캔의 범위가 커져
성능차이가 커진다.
인덱스 선정 및 전략
• 정렬을 자주 해야하는 넓은 범위의 쿼리 패턴이 많다면 클러스터형 인덱스를 고려
• 인덱스 키 값이 고유하다면 유니크 인덱스로 작성
• 키 컬럼의 사이즈는 인덱스 전체 사이즈를 좌우
• 복합 인덱스의 경우 키 컬럼의 순서에 주의
• 인덱스 커버링은 I/O 비용 절감에 매우 효과적이다.
• 꼭 정렬된 순서가 필요 없을 경우 할당 순서 Scan 방식을 유도하는것이 성능상 좋다.
Index Fragmentation
https://blog.devart.com/sql-server-index-fragmentation-in-depth.html
Summary
• DB 튜닝은 1회성이 아닌 지속적으로 이루어져야 한다 (데이터 분포에 따라 또 다시 튜닝이 필요하다)
• 데이터 검색 패턴에 다라 인덱스 디자인도 변경되어야 한다 (영원한 것은 없다)
• 옵티마이저 관점에서 쿼리를 작성하고 비용을 산정할 수 있도록 한다
• 조인 쿼리에서 액세스 패턴에 따라 비용이 기하급수적으로 증가할 수 있다
• 튜닝의 끝은 모델링이다. 모델링만 잘되어도 성능에 좋아진다

More Related Content

Similar to SQL Server Access Patterns

Index Analysis
Index AnalysisIndex Analysis
Index Analysislactrious
 
실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6HyeonSeok Choi
 
Oracle Index
Oracle IndexOracle Index
Oracle IndexJongwon
 
Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문SeungHyun Eom
 
SQL performance and UDF
SQL performance and UDFSQL performance and UDF
SQL performance and UDFJAEGEUN YU
 
그림으로 공부하는 오라클 구조
그림으로 공부하는 오라클 구조그림으로 공부하는 오라클 구조
그림으로 공부하는 오라클 구조Choonghyun Yang
 
AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017
AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017
AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017Amazon Web Services Korea
 
elasticsearch_적용 및 활용_정리
elasticsearch_적용 및 활용_정리elasticsearch_적용 및 활용_정리
elasticsearch_적용 및 활용_정리Junyi Song
 
오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝철민 권
 
AWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil Kim
AWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil KimAWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil Kim
AWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil KimAmazon Web Services Korea
 
새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블
새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블
새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블Gordon Lee
 
MariaDB
MariaDBMariaDB
MariaDBymtech
 
Maria db
Maria dbMaria db
Maria dbymtech
 
2016년 인문정보학 Sql세미나 2/3
2016년 인문정보학 Sql세미나 2/32016년 인문정보학 Sql세미나 2/3
2016년 인문정보학 Sql세미나 2/3in2acous
 
Java collections framework
Java collections frameworkJava collections framework
Java collections framework경주 전
 
Hadoop io
Hadoop ioHadoop io
Hadoop iokidoki
 
Introduction to mongo db
Introduction to mongo dbIntroduction to mongo db
Introduction to mongo dbMinho Kim
 

Similar to SQL Server Access Patterns (20)

Index Analysis
Index AnalysisIndex Analysis
Index Analysis
 
실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6
 
Oracle Index
Oracle IndexOracle Index
Oracle Index
 
Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문Elastic Search (엘라스틱서치) 입문
Elastic Search (엘라스틱서치) 입문
 
AWS RDS, DYNAMO
AWS RDS, DYNAMOAWS RDS, DYNAMO
AWS RDS, DYNAMO
 
SQL performance and UDF
SQL performance and UDFSQL performance and UDF
SQL performance and UDF
 
그림으로 공부하는 오라클 구조
그림으로 공부하는 오라클 구조그림으로 공부하는 오라클 구조
그림으로 공부하는 오라클 구조
 
AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017
AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017
AWS를 통한 빅데이터 기반 비지니스 인텔리전스 구축- AWS Summit Seoul 2017
 
elasticsearch_적용 및 활용_정리
elasticsearch_적용 및 활용_정리elasticsearch_적용 및 활용_정리
elasticsearch_적용 및 활용_정리
 
오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝
 
AWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil Kim
AWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil KimAWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil Kim
AWS Innovate: Best Practices for Migrating to Amazon DynamoDB - Sangpil Kim
 
새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블
새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블
새로쓴 대용량 데이터베이스 솔루션 1분리형일체형테이블
 
MariaDB
MariaDBMariaDB
MariaDB
 
Mongodb index
Mongodb indexMongodb index
Mongodb index
 
Maria db
Maria dbMaria db
Maria db
 
2016년 인문정보학 Sql세미나 2/3
2016년 인문정보학 Sql세미나 2/32016년 인문정보학 Sql세미나 2/3
2016년 인문정보학 Sql세미나 2/3
 
Java collections framework
Java collections frameworkJava collections framework
Java collections framework
 
Hadoop io
Hadoop ioHadoop io
Hadoop io
 
InfiniFlux vs RDBMS
InfiniFlux vs RDBMSInfiniFlux vs RDBMS
InfiniFlux vs RDBMS
 
Introduction to mongo db
Introduction to mongo dbIntroduction to mongo db
Introduction to mongo db
 

SQL Server Access Patterns

  • 1. SQL Server Access Patterns Sungwook Kang
  • 2. Speaker 강성욱 (Sungwook Kang) LA 한인 IT 커뮤니티 http://sqlangeles.com Data Platform 2012 ~ Present http://sqlmvp.kr SQLMVP Sungwook Kang /sqlmvp Sungwook Kang /sqlmvp-sungwookkang
  • 3. Agenda • Data Structure • Index • Access Patterns
  • 4. How to be good at tuning Understand your business • 매일 오후에 실행되는 배치 작업이 있다면? • 반드시 오후에 필요한 작업인가? • 프로덕션 서버에서 해야만 하는가? Tuning for top slow query (Cost of total resource) • 어느것이 더 효율적인가? • 100Page I/O Vs 10000Page I/O? ü 100Page : 초당 10000호출 ü 10000Page : 초당 1번 호출 Understand Optimizer • 사람이 생각하는 방식이 아닌 옵티마이저 관점에서 생각 • 비즈니스를 이해한 다음 옵티마이저에게 올바른 길을 제시한다.
  • 5. Table and Index • Table • Page Type • Data Page Structure • Extents • Index ü Clustered Index ü Non-Clustered Index • Index Depth for Performance • Composite Key
  • 6. Table • 테이블은 하나 이상의 파티션에 포함 • 힙(Heap), 클러스터(Clustered) 인덱스 구조 • 인덱스 페이지는 데이터 행의 열 유형에 따라 하나 이상의 할당 단위로 관리
  • 7. Data Page Structure • Page는 SQL Server에서 기본 저장 단위 • 1Page = 8K (1M = 128Page) • Page Header 부분에서 96Byte의 시스템 정보 저장 • ROW Offsets 부분에서 36Byte의 오프셋 정보 저장 실제 데이터는 8060Byte 8060Byte 초과하는 데이터는 ROW_OVERFLOW_DATA 영역에 저장되고 원래 페이지에는 24Byte의 포인터 정보만 저장 • 페이지 끝에서부터 2Byte씩 배열 형태로 저장 • 행의 논리적 순서를 나타냄 • 정렬이 필요한 경우 행 오프셋 배열로 관리 • PageID : 현재 페이지 주소 • nextPage : 다음 페이지 주소 • prevPage : 이전 페이지 주소 • LSN : 현재 페이지의 변경 로그 시퀀스 • SlotCnt : 현재 페이지의 행 수 • Level : 인덱스 레벨 (0인경우 리프) • IndexId : 페이지의 인덱스 ID (데이터 페이지의 경우 0)
  • 8. Extents • 논리적으로 연속된 8개의 Page 묶음 (64KB) • Mixed Extents (익스텐트에 서로 다른 개체가 섞여 있음) • Uniform Extents (익스텐트에 하나의 개체만 포함) • 테이블이나 인덱스가 생성되면 ü 우선 Mixed Extents에 할당 ü 8페이지 이상 증가시 Uniform Extents에 할당 • 익스텐트 할당 정보는 IAM에서 관리 • 하나의 IAM은 64000 extents 페이지 또는 4GB까지 파일 범위를 처리 • Double linked list구조
  • 9. Page Type Page Type Comments Data 큰 데이터 형식을 제외한 모든 데이터가 저장 Index 인덱스 데이터 저장 Text/Image 큰 데이터 형식과 8KB를 초과하는 가변 데이터 형식 저장 text, ntext, image, nvarcar(max), varchar(amx), varbinary(max), xml 등 GAM (Global Allocation Map) 익스텐트 할당 여부 기록 (1:익스텐트 비어있음, 0 : 익스텐트 할당되어 있음) SGAM (Shared GAM) 혼합 익스텐트 • 1 : 혼합 익스텐트이며 빈 페이지가 존재 • 0 : 혼합 익스텐트가 아니거나 혼합익스텐트 이지만 여유 페이지가 없음 PFS (Page Free Space) 페이지 할당 상태를 기록 IAM (Index Allocation Map) 테이블 또는 인덱스 등의 개체가 할당된 익스텐트에 대한 정보 BCM (Bulk Change Map) 마지막 Backup log 수행 후 대량 로그 작업에 의해 수정된 익스텐트 정보 DCM (Differential Changed Map) 마지막 Backup Database 수행 후 변경된 익스텐트 정보 (1: 마지막 백업 후 변경, 0 : 마지막 백업 후 변경없음)
  • 10. Index TABLE Heap Clustered Index • 클러스터 인덱스가 없음 • 페이지 연결을 고려하지 않음 • 정렬을 고려하지 않음 • 데이터 검색 시 전체 스캔 발생 • 클러스터 인덱스를 생성 • 데이터가 B-Tree 형태로 구조로 저장
  • 11. Clustered Index • 인덱스 키 값을 기반으로 테이블 데이터 행 전체를 정렬해서 저장 • B-Tree 구조 • 리프 레벨에만 데이터 전체가 저장 • 루트와 넌리프 인덱스 페이지에는 인덱스 키 값과 6Byte의 페이지 참조값 (2Byte FileID + 4Byte PageID)만 저장 • 고유 컬럼이면 UNIQUE 인덱스로 생성할 것 권장 ü UNIQUE로 설정되어 있지 않으면 고유한 주소값을 만들기 위해 4Byte의 uniquefier 정보를 추가로 저장 • 키 값으로 정렬된 넓은 범위 검색에 유리 • 테이블당 1개 인덱스 생성 가능
  • 12. Non-Clustered Index • 테이블과 별개로 인덱스 키로만 구성된 별도의 B-Tree 인덱스 영역 생성 • 고유 컬럼이면 UNIQUE 인덱스로 생성할 것 권장 ü UNIQUE로 설정되어 있지 않으면 고유한 주소값을 만들기 위해 4Byte의 uniquefier 정보를 추가로 저장 • 테이블 구조에 따라 인덱스 구조가 조금 다름 ü Heap에서 Non-Clustered 인덱스 생성 ü Clustered 인덱스가 있는 상태에서 Non-Clustered 인덱스 생성 • 테이블에 여러 개의 인덱스 생성 가능 (SQL Server 2008 later : 999개)
  • 13. Non-Clustered Index Non-Clustered Index (Heap) Non-Clustered Index (Clustered) • 인덱스 페이지에는 각 행마다 키 값과 행의 위치값인 8Byte RID (FileID : 2Byte, PageID : 4Byte, SlotNumber : 2Byte)가 인덱스 키로 정렬되어 저장 • RID 값으로 힙 영역에서 인덱스 레벨이 아닌 컬럼을 검색 • 인덱스 페이지에는 RID가 아닌 클러스터 인덱스 키 값 저장 • 클러스터 인덱스가 UNIQUE이면 uniquefier 값은 없음
  • 14. Index Key size, Index depth and Performance • 인덱스 페이지 크기는 8192Byte (데이터 페이지와 동일) • 인덱스 깊이가 깊어 질 수록 성능에 영향을 받음 • 키의 크기가 작을 수록 한 페이지당 저장 데이터 많아져 검색 효율이 높음 • 인덱스 선정에 중요한 기준 (꼭 필요한 컬럼만 할 것) 900Byte key 20Byte key 1p (7row) 7p (22row) 22p (129row) 129p (983row) 983p (7818row) 7818p (62505row) 62505p (499999row) 1p (12row) 12p (2108row) 2108p (499999row)
  • 15. Index Design – Composite Key • 두 개 이상의 컬럼을 Key Column 으로 사용 • 선행 컬럼에 따라 성능 차이가 큼 ü 선행 컬럼으로 Seek 여부를 결정 WHERE OrderDate BETWEEN '2012-02-26' AND '2012-02-27’ AND OrderNum=7000 OrderDate OrderNum … … 2013-02-26 1 … … 2013-02-26 7000 … … 2013-02-27 7000 … … OrderNum OrderDate … … 6998 2013-02-26 6999 2013-02-28 7000 2013-02-26 7000 2013-02-27 7002 2013-02-26 … …
  • 16. Index Design – Composite Key Index_name Index_description Index_keys IX_Tindex_col3_col1 nonclustered located on PRIMARY col3, col1 IX_Tindex_col1_col3 nonclustered located on PRIMARY col1, col3 SELECT col3, col1 FROM dbo.THeap WITH(INDEX (IX_THeap_col3_col1)) WHERE col3 = 1 AND col1 = 5 SELECT col3, col1 FROM dbo.THeap WITH(INDEX (IX_THeap_col1_col3)) WHERE col1 = 5 AND col3 = 1 • col3 + col1과 col1 + col3 트리 높이가 동일하므로 검색 속도가 같다. • 독립적인 col1, col3의 선택도는 다르지만 복합 인덱스col1 + col3, col3 + col1 선택도가 동일하므로 Equal(=) 검색에서는 선택도의 의미가 없으며 성능도 같다. Scan count 1, logical reads 3, physical reads 0 Scan count 1, logical reads 3, physical reads 0
  • 17. Access Type • Sequential Access • Random Access • Scan • Seek • Lookup • Covered Index • Selectivity
  • 18. Sequential Access • 데이터를 정렬된 순서대로 차례대로 읽어가는 방식 • 데이터가 밀집되어 있어 다음에 읽을 데이터 위치가 예측 가능하다 • 모든 검색 비용 동일 ü 큰 범위 검색 유리 ü 포인트로 읽어야 할 때는 불필요한 데이터 까지 읽음 • 데이터가 많을 수록, 시작지점에서 멀어질 수록 성능이 떨어짐 1 2 4 5 7 8 9 10 11 12 13 14 1 9 1
  • 19. Random Access • 데이터의 할당 정보를 이용해서 읽는 방식 • 저장 위치와 상관없이 동일한 시간 소요 • 하나 또는 작은 범위 검색에 유리 ü 14를 검색하기 위해선 1번의 액세스 발생 ü 1~14까지 검색하기 위해선 14번 액세스 발생 A0 A4 A8 AC A1 A5 A9 AD A2 A6 AA AE A3 A7 AB AF Heap 1-A0 2-A1 4-A2 5-A3 7-A4 8-A5 9-A6 10-A7 11-A8 12-A9 13-AA 14-AB 1 9 1
  • 20. Scan • 테이블 전체 또는 인덱스의 리프 레벨을 모두 읽는 방식 • Scan 비용은 테이블의 행 수에 비례. • 사이즈가 작은 테이블이나 검색 범위가 클 때 사용 1 2 4 5 7 8 9 10 11 12 13 14 1 9 1 할당 순서 Scan • IAM에 저장되어 있는 익스텐트 할당 순서대로 읽음 • 정렬이나 인덱스 조각화로 인한 페이지 분할에 크게 영향 받지 않음 인덱스 정렬 Scan • 인덱스 리프 첫 페이지부터 순서대로 읽음 • 페이지 분할이 많이 발생할 수록 성능이 느려짐
  • 21. Seek • 인덱스트리를 타고 하나의 값을 검색하는 방식 • 하나의 값을 검색하고 다른 값을 계속 읽는 것 (Seek + Range) ü Operator를 Seek 로 표시 • Scan과 Seek는 데이터의 많고 적음이 아니라 액세스하는 방법의 정의에 따름 1 2 4 5 7 8 9 10 11 12 13 14 1 9 1 1 2 4 5 7 8 9 10 11 12 13 14 1 9 1 WHERE Idx in (5,12) WHERE Idx > 4
  • 22. Lookup • Non-Clustered 인덱스에서 인덱스 레벨에 저장되어 있지 않은 행을 검색하기 위해 인덱스 레벨의 주소 값으로 직접 Heap 또는 Clustered 인덱스 영역에서 검색 ü RID Lookup : Heap 영역에서 검색 ü Key Lookup : 인덱스 키를 이용한 검색 • Lookup은 인덱스 페이지의 주소값을 이용한 랜덤 액세스 방식으로 실제 I/O 비용이 많이 발생함 A0 A4 A8 AC A1 A5 A9 AD A2 A6 AA AE A3 A7 AB AF Heap 1-A0 2-A1 4-A2 5-A3 7-A4 8-A5 9-A6 10-A7 11-A8 12-A9 13-AA 14-AB
  • 23. Covered Index • 쿼리에 사용된 모든 컬럼이 인덱스로 구성되어 있는것 (인덱스 종류는 아님) • 필요 컬럼을 인덱스 레벨에서 검색할 수 있어 Lookup 이 발생하지 않음. Selectivity • 전체 데이터 집합에서 특정 조건에 의해 필터링 되는 데이터 비율 • 비율이 낮을 수록 선택도가 높다. • 데이터 검색시 옵티마이저가 인덱스를 결정하는 중요한 역할 담당 • 인덱스 선정 또는 쿼리 작성시 신경써야 하는 부분 SELECT COUNT( DISTINCT ColName ) AS DistinctValues, COUNT( ColName ) AS TotalNumberOfValues, COUNT( DISTINCT ColName ) / COUNT( ColName ) * 100.0 AS Selectivity FROM TableName;
  • 24. Access Patterns Type • Table Scan • Cluster Index Scan ü Cluster Index Scan – Ordered false ü Cluster Index Scan – Ordered true • Covered Index Scan ü Covered Index Scan – Ordered false ü Covered Index Scan – Ordered true • Clustered Index Seek + Range Scan • Covered Index Seek + Range Scan • Non-Clustered Index Seek + Range Scan + Lookup ü Non-Clustered Index Seek + Range Scan + Lookup (Heap) ü Non-Clustered Index Seek + Range Scan + Lookup (Clustered) • Non-Clustered Index Scan + Lookup (Heap) • Non-Clustered Index Scan + Lookup (Clustered)
  • 25. Table Scan • Heap 구조 전체를 읽으며 IAM에서만 할당 정보를 알 수 있으므로 할당 순서 Scan 방식 사용 • 스캔이발생하는 조건 ü 소형 테이블 : 인덱스가 존재하여도 테이블이 작으면 스캔으로 작동 ü 적절한 인덱스가 없음 : 필터 조건이 인덱스에 없거나 복합 인덱스의 선행 컬럼이 검색 조건에 없음 ü 넓은 범위 액세스 : Lookup 비용이 너무 높으면 Full Scan 작동 SELECT * FROM dbo.tblx;
  • 26. Clustered Index Scan • 클러스터 인덱스 테이블에서 리프 레벨을 모두 읽는다. • 정렬된 결과 값을 읽어야 하느냐에 따라 Scan 방식이 다르다. • 정렬을 지정하지 않아도 정렬된 결과가 출력될 수도 아닐 수도 있다. ü 스토리지 엔진의 Scan 방식은 사용자가 선택할 수 없다. • 인덱스 키로 정렬해야 한다면 반드시 ORDER BY를 명시 한다. • 정렬이나 데이터 일관성이 꼭 필요하지 않다면 격리 수준을 낮추어서 성능에 유리한 할당 Scan 방식을 유도한다.
  • 27. Clustered Index Scan – Ordered false SELECT * FROM dbo.TIndex Index_name Index_description Index_keys IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1 SELECT * FROM dbo.Tindex with (nolock); SELECT * FROM dbo.Tindex with (tablock); (데이터 순서는 사용자마다 다르게 출력될 수 있음)
  • 28. Cluster Index Scan – Ordered false • 스토리지 엔진이 Scan 방식을 선택할 때 성능 뿐만 아니라 데이터 일관성도 고려 • 정렬 여부 및 격리 수준을 낮추게 되면 할당 순서 Scan을 할 가능성 이 높다. • 인덱스 정렬 스캔이 할당 순서 스캔보다 성능이 느리다. • 인덱스 정렬 Scan 은 데이터가 많거나 인덱스 조각화가 많이 일어날 수록 성능이 느려진다. SELECT * FROM dbo.TIndex SELECT * FROM dbo.Tindex with(nolock); SELECT * FROM dbo.Tindex with (tablock);
  • 29. Cluster Index Scan – Ordered true Index_name Index_description Index_keys IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1 SELECT * FROM dbo.TIndex ORDER BY col3, col1;
  • 30. Cluster Index Scan – Ordered ture SELECT * FROM dbo.TIndex ORDER BY col3, col1; • 옵티마이저가 정렬을 보장하기 위해 ordered 속성은 True로 표시 • 인데스 정렬 Scan 방식만 사용가능
  • 31. Page split, IAM Scan and Index Scan performance [Test Senario] 클러스터 인덱스 테이블에 논리적 조각화를 발생 • 할당 정렬 스캔과 인덱스 정렬 스캔 방식 비교 • 디스크로부터 읽었을 때와 메모리에서 읽을 때 비교 [Conclusion] 데이터가 메모리에 있지 않거나 테이블에서 정렬된 검색결과를 검색해야하는 경우가 아니라면 • ORDER BY를 생략하거나 • WITH (NOLOCK) 힌트를 이용해 격리수준을 최소화하여 • 할당 순서 스캔을 선택하도록 유도하는 것이 성능에 좋다. Disk Memory 할당순서 Scan Index Scan 할당 순서 스캔 Index Scan Flagmentation Ratio (%) 99% 1436ms 16315ms 738ms 756ms 0% 879ms 916ms 745ms 754ms
  • 32. Covered Index Scan • 테이블 구조와 상관없이 비클러스터형 인덱스의 리프 페이지만 검색하는 패턴 • 비클러스터형 인덱스는 인데스 키 컬럼과 Include 컬럼만 저장되어 있어 인덱스 사이즈가 작아 scan 범위가 작다는거 외에는 클러스터형 인덱스 scan 과 동일 • 필요한 컬럼이 인덱스 레벨에 있어 Lookup 과정이 생략되어 쿼리 성능에 향상 Index_name Index_description Index_keys IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1 IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5 SELECT col2, col3, col5 FROM dbo.TIndex SELECT col1, col2, col3, col5 FROM dbo.TIndex • 일반적인 인데스 커버링 (col2를 include로 넣었으므로 인덱스 커버됨) • Scan count 1, logical reads 3986, physical reads 0 • 비클러스터형 인덱스 + 클러스터형 인덱스 • Scan count 1, logical reads 3986, physical reads 0
  • 33. Covered Index Scan SELECT col2, col3, col5 FROM TIndex Index_name Index_description Index_keys IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1 IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
  • 34. Covered Index Scan – Ordered false • ORDER BY를 명시하지 않으면 정렬이 보장 되지 않음 • 스토리지 엔진은 할당 순서 스캔, 인덱스 정렬 스캔 방식을 선택할 수 있음 • 첫 번째 키가 아닌 정렬요소는 false로 표시되고 별도 sort 비용까지 추가됨 • 복합 인덱스에서는 키 순서 중요 SELECT col1, col2, col3, col5 FROM dbo.Tindex ORDER BY col5 Index_name Index_description Index_keys IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1 IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
  • 35. Covered Index Scan – Ordered true • 복합 인덱스의 첫 번째 컬럼으로 정렬을 명시하거나, 집계 쿼리에서 Stream Aggregate 연산자로 실행 계획이 풀리면 우선 정렬을 해야 하므로 정렬속성이 True를 생성 • 집계 쿼리에서 대상 컬럼의 인덱스가 없어 Hach Match Aggregate 연산자로 풀리면 따로 해시 테이블을 만들기 때문에 정렬이 필요없어 Flase 를 생성 SELECT col1, col2, col3, col5 FROM dbo.Tindex ORDER BY col3 SELECT col3, col5, count(*) cnt FROM dbo.Tindex GROUP BY col3, col5 Index_name Index_description Index_keys IX_Tindex_col3_col1 clustered located on PRIMARY col3, col1 IX_Tindex_col3_col5_i_col2 nonclustered located on PRIMARY col3, col5
  • 36. Clustered Index Seek + Range Scan • 클러스터 인덱스의 루트 레벨로부터 트리를 타고 검색한 뒤 데이터가 위치한 리프 레벨에서 범위 스캔 • 인덱스 Seek 후 리프 레벨을 순차적으로 Scan하기 때문에 인덱스 키 순서대로 정렬된 범위 검색에 유리 • 필터링 조건이 첫번째 키라면 처음 인덱스 Seek 후 필터링 조건이나 첫번째 키 컬럼의 분포도가 비용 결정
  • 37. Covered Index Seek + Range Scan • 첫번째 키 컬럼으로 인덱스 Seek한 다음 범위 Scan (클러스터 인덱스 Seek + Range Scan동일) • Lookup 비용이 들지 않음 • 커버링된 컬럼만 포함하므로 모든 데이터를 포함하는 클러스터 인덱스 패턴보다 비용이 낮음 • 두 번째 필터 조건이나 분포도에 따라 비용이 달라짐 SELECT col1, col3 FROM dbo.Tindexrange WHERE col3 = 10
  • 38. Non-Clustered Index Seek + Range Scan + Lookup • 인덱스 Seek + Range Scan 하면서 인덱스 커버링이 되지 않은 컬럼을 검색하기 위해 ü 힙이나 ü 클러스터 인덱스를 Lookup • 일반적으로 포인터 검색 이나 좁은 범위 검색에 적합 • 범위가 넓어질수록 Lookup이 많이 발생하여 랜덤 I/O 비용이 늘어난다 • 랜덤 I/O 비용이 너무 높다고 판단되면 옵티마이저는 테이블 또는 인덱스 Scan을 할 수 있다. • 다음에 읽어야 할 데이터가 동일한 페이지에 있어도 동일 페이지를 다시 액세스 한다.
  • 39. SELECT * FROM dbo.Theap WHERE col5 = '2012-01-01'AND col3 between 1 and 200 Non-Clustered Index Seek + Range Scan + Lookup (Heap) • 쿼리에서 소요되는 비용은 비클러스터 인덱스 높이 + 검색된 로우수 (Lookup 횟수)
  • 40. Non-Clustered Index Seek + Range Scan + Lookup (Clustered) SELECT * FROM dbo.TIndex WHERE col5 = '2012-01-01' AND col3 between 1 and 200 • 쿼리에서 소요되는 비용은 비클러스터 인덱스 높이 + (검색된 로우수X클러스터 인덱스 높이)
  • 41. Non-Clustered Index Scan + Lookup (Heap) SELECT * FROM dbo.Theap WHERE col3 = 10 • 리프 레벨을 모두 스캔하고 리프 레벨 데이터 수 만큼 Lookup 한다 • 랜덤I/O 비용이 많이 발생하므로 테이블 스캔 또는 인덱스를 다시 디자인 하는것이 좋다 • 옵티마이저는 선택도가 충분해도 룩업 비용이 많이 발생하면 스캔할 수도 있다.
  • 42. SELECT * FROM dbo.Tindex WHERE col1 BETWEEN 1 AND 100 Non-Clustered Index Scan + Lookup (Clustered)
  • 43. Strategy for Access patterns • I/O read performance each data selectivity • Query performance for each selectivity
  • 44. I/O read performance each data selectivity
  • 45. I/O read performance each data selectivity
  • 46. Query performance for each selectivity • 좁은 범위 검색 ü Non-Clustered Index Seek + Range Scan + Lookup ü Clustered Index Seek + Range Scan ü Covered Index Seek + Range Scan ü Lookup 패턴은 어느 순간부터 비용이 급격히 늘어나기 때문에 포인트 쿼리 또는 아주 작은 범위 검색에만 사용 • 중간 이상의 범위 검색 ü Covered Index Seek + Range Scan ü Clustered Index Seek + Range Scan ü 이 두 패턴은 선택도에 따라 선형으로 비용이 증가 ü 인덱스 키로 정렬된 결과를 보장하고 필요한 만큼 부분 스캔을 수행하므로 정렬된 범위 검색시 가장 이상적 ü 선택도가 높아질수록 부분 범위 스캔의 범위가 커져 성능차이가 커진다.
  • 47. 인덱스 선정 및 전략 • 정렬을 자주 해야하는 넓은 범위의 쿼리 패턴이 많다면 클러스터형 인덱스를 고려 • 인덱스 키 값이 고유하다면 유니크 인덱스로 작성 • 키 컬럼의 사이즈는 인덱스 전체 사이즈를 좌우 • 복합 인덱스의 경우 키 컬럼의 순서에 주의 • 인덱스 커버링은 I/O 비용 절감에 매우 효과적이다. • 꼭 정렬된 순서가 필요 없을 경우 할당 순서 Scan 방식을 유도하는것이 성능상 좋다.
  • 49. Summary • DB 튜닝은 1회성이 아닌 지속적으로 이루어져야 한다 (데이터 분포에 따라 또 다시 튜닝이 필요하다) • 데이터 검색 패턴에 다라 인덱스 디자인도 변경되어야 한다 (영원한 것은 없다) • 옵티마이저 관점에서 쿼리를 작성하고 비용을 산정할 수 있도록 한다 • 조인 쿼리에서 액세스 패턴에 따라 비용이 기하급수적으로 증가할 수 있다 • 튜닝의 끝은 모델링이다. 모델링만 잘되어도 성능에 좋아진다