Rookiss Part5 데이터베이스 : 북마크 룩업
🙇♀️북마크 룩업
북마크 룩업
- Index Scan이 항상 나쁜 것은 아니고
- Index Seek가 항상 좋은것은 아니다
- 인덱스를 활용하는데 어떻게 느릴 수가 있을까? => 북마크 룩업을 사용하기 때문
🪐차근차근
-
Heap Table[ {PAGE} {PAGE} ]
- CLUSTERED의 경우 INDEX SEEK가 느릴 수가 없다
- NonClustered의 경우, 데이터가 Leaf Page에 없다
- 따라서 한번 더 타고 가야됨
- RID -> Heap Table (Bookbark Lookup)
- Key -> Clustered
SELECT *
INTO TestOrders
FROM Orders;
SELECT *
FROM TestOrders;
CREATE NONCLUSTERED INDEX Orders_Index01
ON TestOrders(CustomerID);
- 인덱스 번호
SELECT Index_id, name
FROM sys.indexes
WHERE object_id = object_id('TestOrders');
- 조회
DBCC IND('Northwind', 'TestOrders', 2);
9000
8960 8968 8969
Heap Table[ {PAGE} {PAGE} ]
- 걸린 시간, 논리적 읽기 수, 실제 로직 경로 확인
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SET STATISTICS PROFILE ON;
🪐분석 시작
- 기본 탐색을 해보자
SELECT *
FROM TestOrders
WHERE CustomerID = 'QUICK';
- 강제로 인덱스를 이용하게 해보자
SELECT *
FROM TestOrders WITH INDEX(Orders_Index01)
WHERE CustomerID = 'QUICK';
논리적 읽기가 늘었음 => 항상 인덱스가 이득인 것은 아니다
🪐룩업을 줄이기 위한 몸부림
SELECT *
FROM TestOrders WITH INDEX(Orders_Index01)
WHERE CustomerID = 'QUICK' AND ShipVia = 3;
ROW가 28개인것을 알지만 ShipVia가 3인것은 모르므로 20개는 뻑이나고 8개만 살아남음
룩업을 줄여보자 경험에 따라 방법이 다 다른다!
복합인덱스를 활용
- CORVERED INDEX
- 모든 경우, 영역을 커버하겠다!
CREATE NONCLUSTERED INDEX Orders_Index01
ON TestOrders(CustomerID, ShipVia);
인덱스 SEEK가 8개만 찾는다
- 둘 다 만족하는것만 찾으니까 리프페이지 자체에서 판단가능
- Heap Table Lookup을 할 필요가 없다
Q) 그럼 조건1 AND 조건2 필요하면, 무조건 INDEX(조건1, 조건2)를 추가해주면 장떙? A) NO! 꼭 그렇지는 않다. DML(INSERT, UPDATE, DELETE) 작업 부하가 증가하게 된다
INCLUDE 활용
CREATE NONCLUSTERED INDEX Orders_Index01
ON TestOrders(CustomerID) INCLUDE (ShipVia);
키 값 자체는 CustomerID만 사용하기에 부담되지 않지만, 리프페이지에다가 ShipVia의 정보를 넣어는 것
데이터 순서에는 영향을 주지 않는다!
- CLUSTERED INDEX 활용
- 위와 같은 눈물겨운 노력에도 답이 없을 떄 사용
- BU! CLUSTERED INDEX는 테이블당 1개만 사용 할 수 있다
🪐결론
NONCLUSTERED INDEX가 악영향을 주는 경우?
- 북마크 룩업이 심각한 부하를 야기할 떄
대안은?
- Covered Index (검색할 모든 칼럼을 포함하겠다)
- Index에다가 Include로 힌트를 남긴다
- Clustered 고려 (단, 1번만 사용할 수 있는 궁극기..) -> NonClustered 악영향을 줄 수 있음