🗂 인덱스 구조 복습

  • Clustered Index

    • 데이터가 정렬된 상태로 Leaf Page에 저장
    • Leaf Page = Data Page
    • 테이블당 1개만 존재 가능
  • Non-Clustered Index

    • Leaf Page에 실제 데이터는 없음
    • 대신 데이터의 위치(RID 또는 키)를 저장
    • 여러 개 생성 가능

⚙ 실습 시작 – 북마크 룩업 발생 케이스 확인

USE Northwind;

-- 테이블 복사
SELECT * INTO TestOrders FROM Orders;

-- 인덱스 생성 (Non-Clustered)
CREATE NONCLUSTERED INDEX Orders_Index01 ON TestOrders(CustomerID);

1️⃣ 기본 조회 (Index 사용 안함)

SELECT * FROM TestOrders WHERE CustomerID = 'QUICK';

📊 결과:

  • Index Scan
  • 논리적 읽기: 20
  • 이유: DB 엔진이 인덱스를 쓰는 것보다 전체 스캔이 빠르다고 판단했기 때문.

2️⃣ 인덱스 강제 사용 (WITH(INDEX))

SELECT * FROM TestOrders WITH(INDEX(Orders_Index01))
WHERE CustomerID = 'QUICK';

📊 결과:

  • Index Seek + Bookmark Lookup
  • 논리적 읽기: 30
  • ❗ 오히려 느려졌다!

📌 왜 느려졌을까?

  • Orders_Index01에는 CustomerID만 있음.
  • 'QUICK'에 해당하는 레코드가 28개 → RID 28개 전부 Heap Table에서 다시 조회
  • 👉 28번 북마크 룩업이 발생!

🧪 북마크 룩업 최적화 전략

✅ 전략 1: Covered Index

-- 기존 인덱스 삭제
DROP INDEX TestOrders.Orders_Index01;

-- CustomerID + ShipVia 복합 인덱스 생성
CREATE NONCLUSTERED INDEX Orders_Index01
ON TestOrders(CustomerID, ShipVia);

-- 조회
SELECT *
FROM TestOrders WITH(INDEX(Orders_Index01))
WHERE CustomerID = 'QUICK' AND ShipVia = 3;

📊 결과:

  • 논리적 읽기: 10
  • 북마크 룩업 없이 바로 찾음

🔍 왜 빠른가?

  • CustomerID와 ShipVia 둘 다 인덱스에 포함되어 있어서 Heap 접근 없이 Leaf Page에서 해결 가능

✅ 전략 2: INCLUDE

-- 기존 인덱스 삭제
DROP INDEX TestOrders.Orders_Index01;

-- CustomerID만 정렬 키, ShipVia는 포함만
CREATE NONCLUSTERED INDEX Orders_Index01
ON TestOrders(CustomerID)
INCLUDE (ShipVia);

-- 조회
SELECT *
FROM TestOrders WITH(INDEX(Orders_Index01))
WHERE CustomerID = 'QUICK' AND ShipVia = 3;

📊 결과:

  • 논리적 읽기: 20
  • 북마크 룩업 감소

📝 설명:

  • 정렬은 CustomerID만 기준
  • ShipVia는 힌트처럼 Leaf Page에 포함되어 있어 다시 Heap 접근 안 함

✅ 전략 3: Clustered Index 활용 (궁극기!)

CREATE CLUSTERED INDEX Orders_Clustered
ON TestOrders(OrderID); -- 정말 중요한 컬럼만!

📌 유의사항:

  • 테이블당 1개만 가능
  • Clustered가 있으면 Non-Clustered는 RID 대신 Clustered 키를 통해 데이터를 찾아야 함

profile
李家네_공부방

0개의 댓글