當優化器所選擇的非聚簇索引只包含查詢請求的一部分欄位時,就需要乙個查詢(lookup)來檢索其他欄位來滿足請求。對乙個有聚簇索引的表來說是乙個鍵查詢(key lookup),對乙個堆表來說是乙個rid查詢(rid lookup)。這種查詢即是——書籤查詢。
書籤查詢根據索引的行定位器從表中讀取資料。故此,除了索引頁面的邏輯讀取外,還需要資料頁面的邏輯讀取。如果查詢的結果是大資料集,建議使用聚簇索引。聚簇索引不用書籤查詢,因為葉子頁面和資料頁相同。
看下面的例項(adventureworks):
select列productid是表上的非聚簇索引,*from
sales.salesorderdetail
assod
where
sod.productid
=776
create非聚簇索ix_salesorderdetail_productid包含列productid以及組成聚簇索引的nonclustered
index
[ix_salesorderdetail_productid]on
[sales].
[salesorderdetail](
[productid
]asc
)
列salesorderid,salesorderdetailid(salesorderid,salesorderdetailid是表上的復合主鍵,
因為非聚簇索引的葉子節點是聚簇索引),並沒有覆蓋查詢的所有列,故此需要乙個書籤查詢。
productid=776查詢結果是228行,但是隨著結果集的增大,需要書籤查詢的非聚簇索引將會被優化器放棄而採用聚簇索引掃瞄,如:
select此查詢結果集是705行,*from
sales.salesorderdetail
assod
where
sod.productid
=793
表'salesorderdetail'。掃瞄計數1,邏輯讀取1240 次
但是如果在表上強制採取非聚簇索引:
表'salesorderdetail'。掃瞄計數1,邏輯讀取2173 次
下面再看一具體例項,來揭示書籤查詢成因以及避免方法。
selecthumanresources.employee表有一非聚簇索引:ak_employee_nationalidnumber([nationalidnumber] asc),執行後的計畫:e.nationalidnumber,e.title,e.hiredate
from
humanresources.employee ase
where
e.nationalidnumber='
693168613
'
為了避免這個書籤查詢,應該把查詢中引用的字段title和hiredate新增到非聚簇索引中,
create執行查詢後的執行計畫:unique
nonclustered
index
ak_employee_nationalidnumber
onhumanresources.employee
( nationalidnumber
asc,title
asc,hiredate
asc)
with
drop_existing
另一避免書籤查詢的方法是用覆蓋索引,
create執行計畫圖:unique
nonclustered
index
ak_employee_nationalidnumber
onhumanresources.employee
( nationalidnumber
asc)include(title,hiredate)
with
drop_existing
SQLSERVER書籤查詢的通俗理解
今晚在網上又看了一下書籤查詢 聚集索引不使用書籤查詢 我的理解 聚集索引 把書裡面的內容放到書籤裡面,指定了聚集索引表列的所有內容 整行記錄 先放到書籤裡面 查詢 當查詢的時候根據書籤目錄,直接查詢書籤,因為內容直接存放在書籤裡面,所以查詢速度很快 修改資料 但是如果要修改資料,那麼,資料庫先找到書...
SQL中如何避免書籤查詢
1 使用聚集索引 對於聚集索引,索引的葉子頁面和表的資料頁面相同。因此,當讀取聚集索引鍵列的值時,資料引擎可以讀取其他列的值而不需要任何導航。例如前面的區間資料查詢的操作,sqlserver通過b樹結構進行查詢是非常快速的。把非聚集索引轉換為乙個聚集索引說起來很簡單。但是,這個例子和大部分可能遇到的...
效能優化 找到SQL SERVER中的書籤查詢
我們在建立索引的時候,對於調節篩選列是大家都能夠注意到的。但是對於包含列檢查會被忽略。從而導致大量的lookup 也就是書籤查詢。那麼我如何才能找出某個表是不是執行了書籤查詢,執行了多少次書籤查詢呢?好訊息是,sql server 有各種各樣的動態管理檢視,其中 sys.dm db index op...