예를 들어, Index(Level, Race)라는 인덱스를 구성했다고 하자. 이때 (56, Human)이라는 조건으로 검색한다고 가정해보자.
이런 경우 "56"이라는 Level은 여러 명이 존재할 수 있으므로, Leaf Page 탐색은 여전히 순차적으로 이루어질 수밖에 없다. 즉, 북마크 룩업을 줄였다 하더라도 인덱스 컬럼 순서에 따라 성능 차이는 존재한다.
USE Northwind;
-- 테이블 복사
SELECT * INTO TestOrders FROM Orders;
-- 더미 데이터 대량 추가 (830 * 1000)
DECLARE @i INT = 1, @emp INT;
SELECT @emp = MAX(EmployeeID) FROM Orders;
WHILE (@i < 1000)
BEGIN
INSERT INTO TestOrders(CustomerID, EmployeeID, OrderDate)
SELECT CustomerID, @emp + @i, OrderDate FROM Orders;
SET @i = @i + 1;
END
-- (EmployeeID, OrderDate) 순서
CREATE NONCLUSTERED INDEX idx_emp_ord
ON TestOrders(EmployeeID, OrderDate);
-- (OrderDate, EmployeeID) 순서
CREATE NONCLUSTERED INDEX idx_ord_emp
ON TestOrders(OrderDate, EmployeeID);
= 일 때-- idx_emp_ord 사용
SELECT * FROM TestOrders WITH(INDEX(idx_emp_ord))
WHERE EmployeeID = 1 AND OrderDate = '19970101';
-- idx_ord_emp 사용
SELECT * FROM TestOrders WITH(INDEX(idx_ord_emp))
WHERE EmployeeID = 1 AND OrderDate = '19970101';
📌 결과: 논리적 읽기 수, 실행 계획 모두 동일
두 컬럼 모두 정확히 일치하는 값으로 조회하는 경우, 컬럼 순서에 관계없이 인덱스를 잘 활용할 수 있다.
BETWEEN을 활용한 범위 검색-- EmployeeID가 선행
SELECT * FROM TestOrders WITH(INDEX(idx_emp_ord))
WHERE EmployeeID = 1 AND OrderDate BETWEEN '19970101' AND '19970103';
-- OrderDate가 선행
SELECT * FROM TestOrders WITH(INDEX(idx_ord_emp))
WHERE EmployeeID = 1 AND OrderDate BETWEEN '19970101' AND '19970103';
📌 결과:
idx_emp_ord: 논리적 읽기 5idx_ord_emp: 논리적 읽기 16🎯 결론: BETWEEN이 선행 컬럼에 적용되면 후행 컬럼은 인덱스 기능을 상실한다. 즉, 선행 조건은 =, 후행 조건에 BETWEEN을 사용하는 것이 가장 효율적이다.
IN-LIST 조건 사용-- IN 조건으로 대체
SELECT * FROM TestOrders WITH(INDEX(idx_ord_emp))
WHERE EmployeeID = 1 AND OrderDate IN ('19970101', '19970102', '19970103');
📌 결과: 논리적 읽기 11
BETWEEN이 선행에 걸렸을 때보다 더 나은 성능 (논리적 읽기 16 → 11)
단, 아래와 같이 선행이 =일 경우는 오히려 BETWEEN이 더 유리함.
-- idx_emp_ord 기준으로는 BETWEEN이 더 효율적
SELECT * FROM TestOrders WITH(INDEX(idx_emp_ord))
WHERE EmployeeID = 1 AND OrderDate IN ('19970101', '19970102', '19970103');
-- 논리적 읽기: 11
-- → BETWEEN 사용 시 논리적 읽기: 5