SQL 查詢性能優(yōu)化 解決書簽查找
更新時(shí)間:2012年08月09日 22:40:05 作者:
當(dāng)優(yōu)化器所選擇的非聚簇索引只包含查詢請(qǐng)求的一部分字段時(shí),就需要一個(gè)查找(lookup)來(lái)檢索其他字段來(lái)滿足請(qǐng)求
先來(lái)看看什么是書簽查找:
當(dāng)優(yōu)化器所選擇的非聚簇索引只包含查詢請(qǐng)求的一部分字段時(shí),就需要一個(gè)查找(lookup)來(lái)檢索其他字段來(lái)滿足請(qǐng)求。對(duì)一個(gè)有聚簇索引的表來(lái)說(shuō)是一個(gè)鍵查找(key lookup),對(duì)一個(gè)堆表來(lái)說(shuō)是一個(gè)RID查找(RID lookup)。這種查找即是——書簽查找。
書簽查找根據(jù)索引的行定位器從表中讀取數(shù)據(jù)。因此,除了索引頁(yè)面的邏輯讀取外,還需要數(shù)據(jù)頁(yè)面的邏輯讀取。
從索引的行定位器到從表中讀取數(shù)據(jù)這之間會(huì)產(chǎn)生一些額外的開銷,本文就來(lái)解決這個(gè)開銷。
先看下我的測(cè)試表結(jié)構(gòu):

其中可以看出 有一個(gè) 聚簇索引 PK_UserID 和一個(gè) 非聚簇索引IX_UserName。
看看產(chǎn)生書簽 查找的效果:
select UserName,Gender from dbo.UserInfo where UserName='userN600'
按上面的 SQL 產(chǎn)生執(zhí)行計(jì)劃 可以看出, 會(huì)產(chǎn)生一個(gè)書簽查找(Key Lookup),如下圖

如果把上面的 SQL 改寫成
select UserName from dbo.UserInfo where UserName='userN600'

可以看出 書簽查找 沒有了。
本SQL 產(chǎn)生書簽查找的 主要原因是 本SQL 優(yōu)化器會(huì)選擇 非聚簇索引IX_UserName,來(lái)執(zhí)生SQL 。IX_UserName 索引不包含 Gender 這個(gè)字段 于是產(chǎn)生個(gè)從索引到 數(shù)據(jù)表的 一個(gè) 查找 即 書簽查找。
解決書簽查找:
方法一、使用一個(gè) 聚簇索引
對(duì)于聚簇索引, 索引的葉子頁(yè)面和表的數(shù)據(jù)頁(yè)面相同,因此,當(dāng)讀取聚簇索引 鍵列的值時(shí),數(shù)據(jù)引擎可以讀取其它列的值而不需要任何行定位,這樣就解決了書簽查找。
對(duì)于這句SQL ( select UserName,Gender from dbo.UserInfo where UserName='userN600')解決了書簽查找的辦法就是在UserName 上 建聚簇索引 ,因?yàn)橐粋€(gè)表只有一個(gè)聚簇索引 ,這就意味著刪除現(xiàn)有聚簇索引(PK_UserID),將會(huì)造成其它從表 中的外鍵約束 要發(fā)生更改,這需要考一些相關(guān)的工作,可能嚴(yán)重影響依賴于現(xiàn)有聚簇索引的其它查詢。
方法二、使用一個(gè) 覆蓋索引
覆蓋索引 是在所有為滿足SQL 查詢不用到達(dá)基本表所需的列 建立的非聚簇索引。如果查詢遇到一個(gè)索引并且完全不需要引用底層數(shù)據(jù)表,那么 該索引可以被認(rèn)為是 覆蓋索引。
對(duì)于這句SQL ( select UserName,Gender from dbo.UserInfo where UserName='userN600') 解決書簽查找的辦法就是 在非聚簇索引IX_UserName 里包含 Gender 字段。
也就是在 建索引時(shí) 用INCLUDE 語(yǔ)句,具體操作如下

用INCLUDE 最好在 以下情況下使用:
1、不希望增加索引鍵的大小,但是仍然可以建一個(gè) 覆蓋索引;
2、打算索引一種不能被索引的數(shù)據(jù)類型(除了文本、NTEXT和圖像);
3、已經(jīng)超過(guò)了一個(gè)索引的關(guān)鍵字列的最大數(shù)量
方法三、使用 索引連接
索引連接 是使用多個(gè)索引之間一個(gè)索引交叉來(lái)完全覆蓋一個(gè)查詢。如果覆蓋索引變的非常寬,那么就可以考慮索引連接。
對(duì)于這句SQL ( select UserName,Gender from dbo.UserInfo where UserName='userN600' and Gender=1)可以在 Gender 上 建一個(gè)非聚簇索引就行了。
對(duì)于這個(gè)例 子,可能 SQL 優(yōu)化器并沒有同時(shí) 選 用非聚簇索引IX_UserName 和 我們新建立在Gender 上的索引,這時(shí)我們可以告知 SQL 優(yōu)化器 同時(shí)使用 這個(gè)兩上索引,操作如下
select Gender,UserName from UserInfo with(index (IX_Gender,IX_UserName)) where UserName='jins' and Gender=0
好了就寫這么多吧.
當(dāng)優(yōu)化器所選擇的非聚簇索引只包含查詢請(qǐng)求的一部分字段時(shí),就需要一個(gè)查找(lookup)來(lái)檢索其他字段來(lái)滿足請(qǐng)求。對(duì)一個(gè)有聚簇索引的表來(lái)說(shuō)是一個(gè)鍵查找(key lookup),對(duì)一個(gè)堆表來(lái)說(shuō)是一個(gè)RID查找(RID lookup)。這種查找即是——書簽查找。
書簽查找根據(jù)索引的行定位器從表中讀取數(shù)據(jù)。因此,除了索引頁(yè)面的邏輯讀取外,還需要數(shù)據(jù)頁(yè)面的邏輯讀取。
從索引的行定位器到從表中讀取數(shù)據(jù)這之間會(huì)產(chǎn)生一些額外的開銷,本文就來(lái)解決這個(gè)開銷。
先看下我的測(cè)試表結(jié)構(gòu):

其中可以看出 有一個(gè) 聚簇索引 PK_UserID 和一個(gè) 非聚簇索引IX_UserName。
看看產(chǎn)生書簽 查找的效果:
select UserName,Gender from dbo.UserInfo where UserName='userN600'
按上面的 SQL 產(chǎn)生執(zhí)行計(jì)劃 可以看出, 會(huì)產(chǎn)生一個(gè)書簽查找(Key Lookup),如下圖

如果把上面的 SQL 改寫成
select UserName from dbo.UserInfo where UserName='userN600'

可以看出 書簽查找 沒有了。
本SQL 產(chǎn)生書簽查找的 主要原因是 本SQL 優(yōu)化器會(huì)選擇 非聚簇索引IX_UserName,來(lái)執(zhí)生SQL 。IX_UserName 索引不包含 Gender 這個(gè)字段 于是產(chǎn)生個(gè)從索引到 數(shù)據(jù)表的 一個(gè) 查找 即 書簽查找。
解決書簽查找:
方法一、使用一個(gè) 聚簇索引
對(duì)于聚簇索引, 索引的葉子頁(yè)面和表的數(shù)據(jù)頁(yè)面相同,因此,當(dāng)讀取聚簇索引 鍵列的值時(shí),數(shù)據(jù)引擎可以讀取其它列的值而不需要任何行定位,這樣就解決了書簽查找。
對(duì)于這句SQL ( select UserName,Gender from dbo.UserInfo where UserName='userN600')解決了書簽查找的辦法就是在UserName 上 建聚簇索引 ,因?yàn)橐粋€(gè)表只有一個(gè)聚簇索引 ,這就意味著刪除現(xiàn)有聚簇索引(PK_UserID),將會(huì)造成其它從表 中的外鍵約束 要發(fā)生更改,這需要考一些相關(guān)的工作,可能嚴(yán)重影響依賴于現(xiàn)有聚簇索引的其它查詢。
方法二、使用一個(gè) 覆蓋索引
覆蓋索引 是在所有為滿足SQL 查詢不用到達(dá)基本表所需的列 建立的非聚簇索引。如果查詢遇到一個(gè)索引并且完全不需要引用底層數(shù)據(jù)表,那么 該索引可以被認(rèn)為是 覆蓋索引。
對(duì)于這句SQL ( select UserName,Gender from dbo.UserInfo where UserName='userN600') 解決書簽查找的辦法就是 在非聚簇索引IX_UserName 里包含 Gender 字段。
也就是在 建索引時(shí) 用INCLUDE 語(yǔ)句,具體操作如下

用INCLUDE 最好在 以下情況下使用:
1、不希望增加索引鍵的大小,但是仍然可以建一個(gè) 覆蓋索引;
2、打算索引一種不能被索引的數(shù)據(jù)類型(除了文本、NTEXT和圖像);
3、已經(jīng)超過(guò)了一個(gè)索引的關(guān)鍵字列的最大數(shù)量
方法三、使用 索引連接
索引連接 是使用多個(gè)索引之間一個(gè)索引交叉來(lái)完全覆蓋一個(gè)查詢。如果覆蓋索引變的非常寬,那么就可以考慮索引連接。
對(duì)于這句SQL ( select UserName,Gender from dbo.UserInfo where UserName='userN600' and Gender=1)可以在 Gender 上 建一個(gè)非聚簇索引就行了。
對(duì)于這個(gè)例 子,可能 SQL 優(yōu)化器并沒有同時(shí) 選 用非聚簇索引IX_UserName 和 我們新建立在Gender 上的索引,這時(shí)我們可以告知 SQL 優(yōu)化器 同時(shí)使用 這個(gè)兩上索引,操作如下
select Gender,UserName from UserInfo with(index (IX_Gender,IX_UserName)) where UserName='jins' and Gender=0
好了就寫這么多吧.
相關(guān)文章
Windows下使用性能監(jiān)視器監(jiān)控SqlServer的常見指標(biāo)
這篇文章主要介紹了Windows下使用性能監(jiān)視器監(jiān)控SqlServer的常見指標(biāo),常見指標(biāo)包括Buffer Cache Hit Ratio、Pages/sec、 Available Bytes、Disk Time、Avg. Disk Queue Length、Processor Time、Processor Queue Length等,需要的朋友可以參考下2015-02-02
Sql Server中的系統(tǒng)視圖詳細(xì)介紹
這篇文章主要介紹了Sql Server中的系統(tǒng)視圖詳細(xì)介紹,本文講解了系統(tǒng)視圖是干什么呢、都定義在哪呢、一些使用例子等內(nèi)容,需要的朋友可以參考下2015-02-02
MS-SQL Server 中單引號(hào)的兩種處理方法
MS-SQL Server 中單引號(hào)的兩種處理方法...2007-01-01
詳解SQL Server表和索引存儲(chǔ)結(jié)構(gòu)
這篇文章主要介紹了詳解SQL Server表和索引存儲(chǔ)結(jié)構(gòu),有助于大家對(duì)SQL存儲(chǔ)方式有深入的理解,參考學(xué)習(xí)下吧。2017-11-11
SQLSERVER語(yǔ)句的執(zhí)行時(shí)間顯示的統(tǒng)計(jì)結(jié)果是什么意思
在SQL語(yǔ)句調(diào)優(yōu)的時(shí)候,大部分都會(huì)查看語(yǔ)句執(zhí)行時(shí)間,究竟SQLSERVER顯示出來(lái)的統(tǒng)計(jì)結(jié)果是什么意思,接下來(lái)為您一一解釋,感興趣的朋友可以了解下2013-01-01
MSSQLSERVER跨服務(wù)器連接(遠(yuǎn)程登錄)的示例代碼
這篇文章主要介紹了MSSQLSERVER跨服務(wù)器鏈接服務(wù)器的方法,大家參考使用2013-11-11
SQL Server數(shù)據(jù)庫(kù)中批量導(dǎo)入數(shù)據(jù)的四種方法總結(jié)
數(shù)據(jù)導(dǎo)入一直是項(xiàng)目人員比較頭疼的問(wèn)題。其實(shí),在SQL Server中集成了很多成批導(dǎo)入數(shù)據(jù)的方法,接下來(lái)為大家介紹下常用的四種批量導(dǎo)入數(shù)據(jù)的方法,感興趣的各位可以參考下哈2013-03-03
SQLServer 數(shù)據(jù)導(dǎo)入導(dǎo)出的幾種方法小結(jié)
在涉及到SQL Server編程或是管理時(shí)一定會(huì)用到數(shù)據(jù)的導(dǎo)入與導(dǎo)出, 導(dǎo)入導(dǎo)出的方法有多種,結(jié)合我在做項(xiàng)目時(shí)的經(jīng)歷做一下匯總2010-06-06

