標籤:style blog http os 使用 sp strong 檔案 資料
接下來的文章是記錄自己曾經的盲點,同時也透漏了自己的發展曆程(可能發展也算不上,只能說是瞎混)。當然,一些盲點也在工作和探究過程中慢慢有些眉目,現在也願意發揚部落格園的奉獻精神,拿出來和大家分享一下。
在剛開始工作時候,總以自己有個“高科技”的工作,而感到特別神氣,經常在其他人面前說一些讓別人覺得高大上的措辭,到後來會在學妹面前炫耀的講一下SQL Server的執行計畫,這個時候別說執行計畫了,就是SQL的最佳化對我來說還是個新鮮的事物,總是以自己能正確查出結果而沾沾自喜。然而,當真有不經世事的學妹會問我,執行計畫是什麼,我的回答:“就是......”,說的什麼,我自己都不知道。
開門見山,直接入題
在查看SQL Sever執行計畫的過程中,你是否曾經也和我一樣,看到索引尋找就欣喜若狂,萬事大吉了呢,從來不會理會RID尋找,鍵尋找為何物,更不會管他們究竟是什麼。但是,作為程式猿的我,為了能進化為人,我不得不去搞明白書籤(RID,索引值)為何物。
書籤尋找出現的情況:書籤尋找總是伴隨著非叢集索引的尋找而出現,但並不是所有的非叢集索引都會引起書籤尋找。在表以堆(不含叢集索引)的形式儲存的時候,書籤尋找為RID尋找,當表以樹(含叢集索引)的形式儲存時,書籤尋找為鍵尋找。
書籤尋找為何物:當SQL Server查詢最佳化工具使用非叢集索引尋找時,當該索引沒有完全覆蓋查詢列和返回列時,就會引起書籤尋找。
RID是什麼:當表以堆的形式儲存的時候,資料行的物理位置是不會(嚴謹的說是很少)變動的,正是因為很少變動,所以,可以通過一個地址來唯一確定一行,又因為資料庫的每一行一定儲存在某一頁上,而某一頁又一定在某一資料庫檔案中,所以就可以通過檔案號:頁號:行號(如:1:22:14,指的就是第1個資料庫檔案的第22頁中的第14行)。
索引值書籤是什麼:當表以樹的形式儲存時,也就是說,當表含有叢集索引時,表中的資料行是會移動的,所以,RID是不能一直定位在同一行的。這個時候就需要通過叢集索引鍵來定位一行,這個叢集索引鍵就是索引值書籤。
下面我們可以通過例子來認識下書籤尋找,以及它們對效能的影響:
我們還用 SQL Server執行計畫那些事兒(1)——雜湊、合并、嵌套聯結的選擇中的例子(刪除所有索引)。
1.我們先建立非叢集索引
create nonclustered index non_index_headers_buyDate on headers(BuyDate)
然後執行
select ID,BuyDate from Headers where BuyDate>‘2008-12-28‘
註:該例子僅僅為了說明情況,不含實際意義。
分析:在不含叢集索引的表中,因為這個非叢集索引中沒有覆蓋ID列,所以要通過RID進行尋找。
2.建立叢集索引
create clustered index index_headers_ID on headers(ID)
然後執行上面查詢語句
select ID,BuyDate from Headers where BuyDate>‘2008-12-28‘
分析:是不是覺得很奇怪?不奇怪,因為非叢集索引的覆蓋列包含,非叢集索引的鍵列、非叢集索引包含的列以及叢集索引的鍵列。因此,ID和BuyDate為非叢集索引覆蓋列,所以僅通過索引頁就可以查出結果,沒必要再通過任何書籤尋找。
3.執行下面SQL語句
select ID,BuyDate,Discount from Headers where BuyDate>‘2008-12-28‘
分析:因為此時的表中有叢集索引,又因為非叢集索引沒有覆蓋Discount列,所以會引起鍵尋找。
4.書籤尋找對查詢效能的影響到底有多大呢 ?
建立非叢集索引,讓其覆蓋Discount列
create nonclustered index non_index_headers_buyDate_include on headers(BuyDate) include(Discount)
然後執行例子3中的查詢語句
select ID,BuyDate,Discount from Headers where BuyDate>‘2008-12-28‘
分析:因為此時非叢集索引已經覆蓋了,查詢列和結果列,故沒有書籤尋找。另外,此時邏輯讀取次數已經明顯比之前小了很多,可見書籤尋找是很耗資源的,甚至會使索引失效,從而引起全表掃描。
總結
1.只有在用到非叢集索引尋找時,並且尋找列和返回列沒有完全被索引覆蓋時,才會引起書籤尋找。
2.書籤尋找是非常耗費資源的,甚至會使索引失效。
3.可以通過讓非叢集索引覆蓋查詢列和返回列來消除書籤尋找。
SQL Server執行計畫那些事兒(3)——書籤尋找