SQL Server 의 초점 필터 인덱스 를 자세히 설명 합 니 다.

머리말
이 절 에서 우 리 는 색인 지식 을 계속 이야기 합 니 다.앞에서 우 리 는 색인,비 집합 색인 과 커버 색인 등 을 모 았 습 니 다.그 중에서 여과 색인 도 있 습 니 다.색인 을 통 해 우 리 는 조회 성능,짧 은 내용 을 향상 시 키 고 깊이 이해 할 수 있 습 니 다.
색인 필터,검색 조건 에서 비 집합 색인 만 들 기(1)
필터 색인 은 SQL 2008 의 새로운 기능 으로 표 의 일부 줄 에 적용 되 기 때문에 필터 색인 을 이용 하여 검색 을 높 일 수 있 습 니 다.전체 표 스 캔 에 비해 색인 유지 와 색인 저장 의 대 가 를 줄 일 수 있 습 니 다.색인 에 WHERE 조건 을 적용 할 때 색인 을 필터 합 니 다.즉,다음 과 같은 형식 을 만족 시 키 는 것 이다.

CREATE NONCLUSTERED INDEX <index name>
ON <table> (<columns>)
WHERE <criteria>;
GO
다음은 간단 한 조 회 를 보 겠 습 니 다.

USE AdventureWorks2012
GO
SELECT SalesOrderDetailID, UnitPrice
FROM Sales.SalesOrderDetail
WHERE UnitPrice > 2000
GO
상기 열 에 어떠한 색인 도 만 들 지 않 았 습 니 다.물론 SalesOrder DetailID 가 기본적으로 만 든 집합 색인 을 제외 하고 실 행 된 조회 계획 은 반드시 홈 키 가 만 든 집합 색인 스 캔 이 라 고 추측 할 수 있 습 니 다.다음 과 같 습 니 다.

위 에서 말 했 듯 이 이 때 는 검색 조건 에 색인 을 만 들 지 않 았 기 때문에 이 때 는 반드시 홈 키 가 만 든 집합 색인 을 가 야 합 니 다.그 다음 에 우 리 는 먼저 UnitPrice 열 에 비 집합 색인 을 만들어 검색 성능 을 향상 시 킵 니 다.

CREATE NONCLUSTERED INDEX idx_SalesOrderDetail_UnitPrice
ON Sales.SalesOrderDetail(UnitPrice)
이때 우 리 는 다시 두 사람 이 지출 을 조회 하 는 것 을 비교 해 보 자.

USE AdventureWorks2012
GO
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
SELECT SalesOrderDetailID, UnitPrice
FROM AdventureWorks2012.Sales.SalesOrderDetail WITH(INDEX([PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID]))
WHERE UnitPrice > 2000
GO
SELECT SalesOrderDetailID, UnitPrice
FROM Sales.SalesOrderDetail WITH(INDEX([idx_SalesOrderDetail_UnitPrice]))
WHERE UnitPrice > 2000

이때 검색 조건 에 비 집합 색인 을 만 든 후 검색 비용 이 90%이상 올 랐 습 니 다.비 집합 색인 도 홈 키 가 만 든 집합 색인 을 참조 하기 때문에 이 럴 때 북 마크 룩 업 이나 키 룩 업 이 찾 지 않 습 니 다.다음 에 우 리 는 조건 이 있 는 비 집합 색인 즉 필터 색인 을 추가 합 니 다.

CREATE NONCLUSTERED INDEX idxwhere_SalesOrderDetail_UnitPrice
ON Sales.SalesOrderDetail(UnitPrice)
WHERE UnitPrice > 1000
이때 필터 색인 을 만 든 후 이전 비 집합 색인 성능 과 비용 차 이 를 살 펴 보 겠 습 니 다.

USE AdventureWorks2012
GO
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
SELECT SalesOrderDetailID, UnitPrice
FROM AdventureWorks2012.Sales.SalesOrderDetail WITH(INDEX([idx_SalesOrderDetail_UnitPrice]))
WHERE UnitPrice > 2000
SELECT SalesOrderDetailID, UnitPrice
FROM Sales.SalesOrderDetail WITH(INDEX([idxwhere_SalesOrderDetail_UnitPrice]))
WHERE UnitPrice > 2000

이때 우 리 는 만 든 비 집합 필터 색인 이 전통 적 으로 만 든 비 집합 색인 에 비해 우리 의 조 회 는 절반 가까이 줄 어 들 었 다 는 것 을 알 고 있다.
유일한 필터 인덱스
유일한 필터 색인 은 모든 열 에 유일 하고 비어 있 지 않 아야 합 니 다.(하나의 NULL 만 존재 할 수 있 습 니 다)또한 좋 은 해결 방안 입 니 다.따라서 유일한 필터 색인 을 만 들 때 NULL 값 을 제외 해 야 합 니 다.예 를 들 어 다음 과 같 습 니 다.

CREATE UNIQUE NONCLUSTERED INDEX uq_fix_Customers_Email
ON Customers(Email)
WHERE Email IS NOT NULL
GO
필터 인덱스 결합 INCLUDE
추가 열 을 추가 할 때 기본 키 로 만 든 집합 색인 을 사용 할 때 집합 색인 검색 을 한 다음 검색 조건 에서 필터 색인 을 만 듭 니 다.이 필터 색인 을 강제로 사용 할 때 추가 열 을 추가 하기 때문에 기본 표 로 돌아 가서 데 이 터 를 가 져 와 야 하기 때문에 Key Lookup 에서 찾 습 니 다.다음 과 같 습 니 다.

USE AdventureWorks2012
GO
SELECT SalesOrderDetailID, UnitPrice, UnitPriceDiscount
FROM Sales.SalesOrderDetail
WHERE UnitPrice > 2000
GO

이때 우 리 는 INCLUDE 로 추가 열 을 포함 해 야 한다.

CREATE NONCLUSTERED INDEX [idx_SalesOrderDetail_UnitPrice] ON Sales.SalesOrderDetail(UnitPrice) INCLUDE(UnitPriceDiscount)
필터 색인 을 만 들 고 추가 열 을 포함 합 니 다.

CREATE NONCLUSTERED INDEX [idxwhere_SalesOrderDetail_UnitPrice] ON Sales.SalesOrderDetail(UnitPrice) INCLUDE(UnitPriceDiscount)
WHERE UnitPrice > 2000
다음은 필터 색인 을 추가 하 는 것 과 필터 색인 을 추가 하지 않 는 것 을 비교 하 는 동시에 추가 열의 성능 조회 차 이 를 포함한다.

SELECT SalesOrderDetailID, UnitPrice, UnitPriceDiscount
FROM AdventureWorks2012.Sales.SalesOrderDetail WITH(INDEX([idx_SalesOrderDetail_UnitPrice]))
WHERE UnitPrice > 2000 
SELECT SalesOrderDetailID, UnitPrice, UnitPriceDiscount
FROM Sales.SalesOrderDetail WITH(INDEX([idxwhere_SalesOrderDetail_UnitPrice]))
WHERE UnitPrice > 2000

이때 추가 열 을 INCLUDE 로 포함 하 는 성능 도 어느 정도 개선 됐다.
색인 필터,홈 키 에 비 집합 색인 만 들 기(2)
첫 번 째 사례 열 에서 우 리 는 검색 열 에 비 집합 색인 을 직접 만 들 수 있 습 니 다.그 유형 은 디지털 형식 이기 때문에 검색 조건 이 문자 형식 이 라면?첫 번 째 선택 은 지금 테스트 표를 만 듭 니 다.

USE TSQL2012
GO
CREATE TABLE dbo.TestData 
(
  RowID    integer IDENTITY NOT NULL, 
  SomeValue  VARCHAR(max) NOT NULL,   
  StartDate  date NOT NULL,
  CONSTRAINT PK_Data_RowID
    PRIMARY KEY CLUSTERED (RowID)
);
테스트 데이터 10 만 개 추가

USE TSQL2012
GO
INSERT dbo.TestData WITH (TABLOCKX)
  (SomeValue, StartDate)
SELECT
  CAST(N.n AS VARCHAR(max)) + 'JeffckyWang',
  DATEADD(DAY, (N.n - 1) % 31, '20140101')
FROM dbo.Nums AS N
WHERE 
  N.n >= 1 
  AND N.n < 100001;
표 TestData 에서 SomeValue='JeffckyWang'을 가 져 올 필요 가 있다 면,SomeValue 에 비 집합 색인 을 만 들 고 필 터 를 하려 면 다음 과 같 습 니 다.

USE TSQL2012
GO
CREATE NONCLUSTERED INDEX idx_noncls_somevalue
ON dbo.TestData(SomeValue)
WHERE SomeValue = 'JeffckyWang'

업데이트
SQL Server 는 생 성 색인 크기 에 제한 이 있 으 며 최대 900 바이트 이 며 위 에 직접 쓴 VARCHAR(MAX)이기 때문에 오류 가 발생 할 수 있 습 니 다.
이 때 우 리 는 홈 키 에 비 집합 색인 을 만 듭 니 다.홈 키 RowID 에 필터 색인 을 만 들 고 SomeValue='Jeffcky Wang'을 만 든 다음 데 이 터 를 되 돌려 줍 니 다.다음 과 같 습 니 다.

CREATE NONCLUSTERED INDEX idxwhere_noncls_somevalue
ON dbo.TestData(RowID)
WHERE SomeValue = 'JeffckyWang'
필터 색인 생 성 전후 조회 계획 결 과 를 비교 해 보 겠 습 니 다.

USE TSQL2012
GO
SELECT RowID, SomeValue, StartDate 
FROM dbo.TestData WITH(INDEX([idx_pk_rowid]))
WHERE SomeValue = 'JeffckyWang'
SELECT RowID, SomeValue, StartDate 
FROM dbo.TestData WITH(INDEX([idxwhere_noncls_somevalue]))
WHERE SomeValue = 'JeffckyWang'

그리고 이전에 배 운 것 과 결합 하여 Key Lookup 을 제거 하고 만 든 필터 색인 을 INCLUDE 합 니 다.

CREATE NONCLUSTERED INDEX [idxwhere_noncls_somevalue] ON dbo.TestData(RowID) INCLUDE(SomeValue,StartDate) 
WHERE SomeValue = 'JeffckyWang'

이 를 통 해 알 수 있 듯 이 조회 조건 에 대한 필터 색인 을 만 들 든 메 인 키 에 대한 필터 색인 을 만 들 든 우 리 는 이전에 배 운 것 과 결합 하여 조회 성능 을 향상 시 킬 수 있다.
우 리 는 처음부터 필터 색인 을 만 드 는 것 에 대해 이야기 해 왔 습 니 다.그러면 필터 색인 의 장점 을 만 드 는 조건 은 무엇 입 니까?
(1)비 집합 색인 을 통 해 만 들 수 있 습 니 다.
(2)보기 에 필터 색인 을 만 들 려 면 이 보 기 는 지속 적 인 보기 여야 합 니 다.
(3)전체 텍스트 인덱스 에 필터 인덱스 를 만 들 수 없습니다.
필터 인덱스 의 장점
(1)색인 유지 비용 감소:증가,삭제,변경 등 작업 에 대해 대가 가 그리 비 싸 지 않 습 니 다.색인 을 걸 러 내 는 재 구축 에 시간 이 많이 걸 리 지 않 기 때 문 입 니 다.
(2)저장 비용 감소:색인 을 걸 러 내 는 저장 공간 이 매우 작다.
(3)더욱 정확 한 통계:WHERE 조건 에서 필터 색인 을 만 드 는 것 이 전체 표 통계 결과 보다 더욱 정확 하 다.
(4)조회 성능 최적화:조회 계획 을 통 해 효율 성 을 알 수 있다.
여기까지 만 해도 색인 을 걸 러 내 는 장점 과 장점 이 하늘 로 치 켜 세 웠 다 는 것 이 단점 이다.
필터 인덱스 단점
가장 큰 단점 은 조회 조건 의 제한 이다.그 조회 조건 은 한정된다

<filter_predicate> ::=  
  <conjunct> [ AND <conjunct> ] 
<conjunct> ::= 
  <disjunct> | <comparison>  
<disjunct> ::= 
    column_name IN (constant ,...n)
필터 조건 은 AND,|,IN 에 한 정 됩 니 다.비교 조건 은{IS|IS NOT|=|<>|!그래서 다음 과 같이 LIKE 를 이용 하면 안 돼 요.

CREATE NONCLUSTERED INDEX [idxwhere_noncls_somevalue] ON dbo.TestData(RowID) INCLUDE(SomeValue,StartDate) 
WHERE SomeValue LIKE 'JeffckyWang%'

아래 와 같이 할 수 있다

USE AdventureWorks2012
GO
CREATE NONCLUSTERED INDEX idx_SalesOrderDetail_ModifiedDate
ON Sales.SalesOrderDetail(ModifiedDate)
WHERE ModifiedDate >= '2008-01-01' AND ModifiedDate <= '2008-01-07'
GO
아래 와 같이 는 안 된다

CREATE NONCLUSTERED INDEX idx_SalesOrderDetail_ModifiedDate
ON Sales.SalesOrderDetail(ModifiedDate)
WHERE ModifiedDate = GETDATE()
GO

변수 가 필터 인덱스 에 미 치 는 영향
검색 조건 에서 직접 정 의 된 문자열 을 만 듭 니 다.다음 과 같 습 니 다.

CREATE NONCLUSTERED INDEX idxwhere_SalesOrderDetail_UnitPrice
ON Sales.SalesOrderDetail(UnitPrice)
WHERE UnitPrice > 1000
변 수 를 정의 한다 면 변 수 를 이용 하여 비교 하 는 것 은 어 떨 까요?우선 필터 색인 을 만 듭 니 다.

CREATE NONCLUSTERED INDEX idx_SalesOrderDetail_ProductID 
ON Sales.SalesOrderDetail (ProductID)
WHERE ProductID = 870
변 수 를 이용 하여 검색 조건 과 비교 하여 필터 색인 을 강제로 사용 합 니 다(기본 값 으로 집합 색인)

USE AdventureWorks2012
GO
DECLARE @ProductID INT 
SET @ProductID = 870 
SELECT ProductID 
FROM Sales.SalesOrderDetail WITH(INDEX([idx_SalesOrderDetail_ProductID]))
WHERE ProductID = @ProductID

실행 계획 을 조회 하 는 중 오류 가 발생 했 습 니 다.이때 OPTION 을 추가 하여 재 컴 파일 해 야 합 니 다.다음 과 같 습 니 다.

USE AdventureWorks2012
GO
DECLARE @ProductID INT 
SET @ProductID = 870 
SELECT ProductID 
FROM Sales.SalesOrderDetail
WHERE ProductID = @ProductID
OPTION(RECOMPILE)

상기 변 수 를 이용 하여 마지막 으로 OPTION 을 통 해 SQL Server 2012 에 재 컴 파일 하여 테스트 할 수 있 습 니 다.다른 버 전 은 알 수 없 으 며 참고 자료[The Pains of Filtered Indexes].
총결산
이 절 에서 우 리 는 색인 을 걸 러 서 조회 성능 을 향상 시 키 는 동시에 서로 다른 장면 과 그 사용 장점 과 뚜렷 한 단점 도 제시 했다.짧 은 내용,깊 은 이해,우리 다음 절 에 다시 만 나 자,good night.
이상 은 본 고의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 댓 글 을 남 겨 서 교류 할 수 있 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다!

좋은 웹페이지 즐겨찾기