본 포스트는 Microsoft TechNet의 [논리 및 물리 연산자 참조]내용을 참고하여 정리한 내용이다.
Bookmark Lookup 연산자는 책갈피(행 ID 또는 클러스터링 키)를 사용하여 테이블이나 클러스터형 인덱스에서 해당 행을 조회한다. Argument 열에는 테이블이나 클러스터형 인덱스에서 행을 조회할 때 사용하는 책갈피 레이블이 포함된다. Argument 열에는 행을 조회하는 테이블 또는 클러스터형 인덱스의 이름도 포함된다. WITH PREFETCH 절이 Argument 열에 나타나는 경우에 쿼리 프로세서에서는 테이블 또는 클러스터형 인덱스에서 책갈피를 조회할 때 비동기 사전 인출(미리 읽기)을 사용하는 것을 최적의 방법으로 결정하게 된다.
SQL Server 2005 이후 버전에서는 Bookmark Lookup이 사용되지 않는다. 대신 Clustered Index Seek 및 RID Lookup이 책갈피 조회 기능을 제공하며, SQL Server 2005 서비스 팩 2 이후에서는 Key Lookup 연산자도 이 기능을 제공한다.
그래프 실행 계획 아이콘
[주인장의 말.말.말]
위의 내용은 BOL을 인용한 것으로 처음 접하는 사람에게는 이해하기 힘들 수 있을 것이다. 블로그 주인이 Bookmark Lookup을 부연 설명하자면, 내가 Select하고자 하는 컬럼이 인덱스에 없을 경우 넌클러스터드 인덱스의 키 값을 가지고 힙 페이지 (혹은 클러스터형 인덱스가 있는 테이블일 경우는 클러스터형 인덱스를) 뒤지는 것을 의미한다. 따라서 힙이나 클러스터형 인덱스를 찾아가는 과정의 추가적인 Page I/O가 발생하게 된다.
이는 마치 Oracle에서 인덱스 영역에 저장되어 있는 rowid를 가지고 데이터 블록을 엑세스하는 과정과 같다.
하지만 내가 Select하고자 하는 컬럼이 모두 인덱스에 있을 때, 즉 인덱스가 모두 커버할 수 있을 때 - 이를 유식한 말로 Covered Index라고 한다. - 는 Bookmark Lookup이 발생하지 않게 될 것이다. 이는 아래의 예에서 확인해 보도록 하자.
BookMark Lookup 연산자의 예 (이 테스트는 SQL Server 2000에서 이루어졌다)
먼저, 앞서 소개한 dbo.idxinfo_v 뷰를 조회하여 authors 테이블의 인덱스를 먼저 확인해 본다.
SELECT Owner, TableName, IndexName, ClusterType, UniqueType, IndexType, AllColName |
조회 결과
Owner | TableName | IndexName | ClusterType | UniqueType | IndexType | AllColName |
dbo | authors | UPKCL_auidind | CLUSTERED | PRIMARY KEY | CONSTRAINT | au_id |
dbo | authors | aunmind | NONCLUSTERED | INDEX | au_lname, au_fname |
이제 아래의 SQL을 실행해 보자. 실행 계획에서 Bookmark Lookup을 확인 할 수 있을 것이다.
USE pubs
SET NOCOUNT ON
SET SHOWPLAN_ALL ON
SELECT *
SET SHOWPLAN_ALL OFF |
텍스트 실행 계획
SttText |
SELECT * FROM authors AS a WHERE au_lname LIKE 'St%' ORDER BY a.au_lname DESC |--Bookmark Lookup(BOOKMARK:([Bmk1000]), OBJECT:([pubs].[dbo].[authors] AS [a])) |--Index Seek(OBJECT:([pubs].[dbo].[authors].[aunmind] AS [a]), SEEK:([a].[au_lname] >= 'Ss' AND [a].[au_lname] < 'Su'), WHERE:(like([a].[au_lname], 'St%', NULL)) ORDERED BACKWARD) |
그래픽 실행 계획
|
다음의 앞에서 언급한 Covered Index의 예이다.
위 SQL에서 달라진 것은 Select한 컬럼이 모두 인덱스에 있다는 점 뿐이다.
USE pubs
SET NOCOUNT ON
SET SHOWPLAN_ALL ON
SELECT a.au_lname, a.au_lname
SET SHOWPLAN_ALL OFF |
텍스트 실행 계획
SttText |
SELECT a.au_lname, a.au_lname FROM authors AS a WHERE au_lname LIKE 'St%' ORDER BY a.au_lname DESC |--Index Seek(OBJECT:([pubs].[dbo].[authors].[aunmind] AS [a]), SEEK:([a].[au_lname] >= 'Ss' AND [a].[au_lname] < 'Su'), WHERE:(like([a].[au_lname], 'St%', NULL)) ORDERED BACKWARD) |
그래픽 실행 계획
|