1. 程式人生 > >T-SQL執行內幕(9)——資料訪問

T-SQL執行內幕(9)——資料訪問

本文屬於SQL Server T-SQL執行內幕系列


    在執行樹的葉子端(通常就是圖形化執行計劃每個分支的最右端),一般是實際訪問資料的操作符。當呼叫這些操作符上的next()方法時,會返回表或者索引上的實際資料。資料訪問通常有三類可能的操作符:

  • Scan:

    各類掃描,掃描操作會在資料上迴圈訪問所有的行。它永遠不會定位一個特定的行,取而代之的是掃描整個資料集。在執行計劃中常見的掃描操作符有:聚集索引掃描(clustered_index_scan)、非聚集索引掃描(nonclustered_index_scan

)、表掃描(table_scan)、遠端索引掃描(remote_index_scan)和遠端掃描(remote_scan)。由於應用在不同的資料來源(表、索引、遠端連結伺服器),所以這些掃描不是相同的操作符,但是都有相同的端對端掃描行為。同時由於需要讀取整個資料集,所以往往都是高開銷操作,理想情況下,僅適合資料倉庫查詢。

  • Seek:

    查詢操作,通過鍵直接定位一行資料,因此只能應用在B-Tree結構的資料來源中,也就是聚集索引和非聚集索引上。如果一個索引是複合索引(多列),那麼查詢操作僅對索引鍵的最左邊那列進行操作,比如一個索引有且順序為ABC三列,而語句中出現如where A=’a’ AND B=’b’ AND C=’c’或Where A=’a’ and B=’b’或者Where A=’a’這種都可以使用到該索引進行查詢操作,但是如果Where只有B=’b’或者C=’c’等沒有A列出現,則索引不能進行查詢操作,通常就是使用掃描。注意從SQL 2005開始Where條件的列順序已經無關緊要。

    另外,查詢操作也適用於範圍查詢,比如上面的索引,如果Where A >’a’ and A<’z’是可以用到索引查詢,但是如果WhereA=’a’ and B>’b’ and B<’z’這種,對B的範圍查詢並不會用到索引查詢,僅會對A=’a’進行查詢。

    執行計劃中可能出現Clustered_Index_Seek或者Remote_Index_Seek這類操作符,他們同樣由於不同的資料來源所以是不同的操作型別,但是依舊可以通過鍵值來高效定位某個資料或者某個範圍值。

    前面提到過,查詢操作僅能發生在B-Treee結構上,所以不存在堆查詢。對於絕大部分OLTP系統而言,應該廣泛使用這種方式查詢資料。

  • Bookmark Lookup:

    書籤查詢,一種特殊的資料訪問操作符,可以基於特定型別的值(稱為書籤)高效定位一行資料。但是僅能由資料庫引擎執行,使用者無法通過語句或者hints來進行強制。同時跟查詢和掃描不同的是它永遠不是主要的資料訪問操作符,只是用來查詢之前一個查詢或掃描操作訪問過的資料。簡單來說就是協助查詢或掃描操作進行額外的資料獲取。書籤查詢可以應用在任何資料結構,包括堆和B-Tree。分別稱為RID Lookup(RID查詢)和Key Lookup(鍵值查詢)。注意從SQL 2008開始,書籤查詢這個名字已經被RID 查詢和鍵值查詢所替代,書籤查詢僅作為這兩個查詢的統稱。

    從效能優化方面來說,出現書籤查詢意味著你的非聚集索引無法覆蓋特定查詢所用到的列,對於大部分情況,可以通過修改現有非聚集索引來去除書籤查詢,畢竟它往往意味著引入了額外的I/O。不過也有一些情況,比如SELECT *,非聚集索引往往不會也不應該覆蓋所有的列,所以這個時候,可能書籤查詢甚至聚集索引操作反而更高效。

    嚴格來說,所有用於增、刪、改資料的操作符同樣都是資料訪問操作符。在觸發器中,inserted和deleted分別使用InsertedScanDeleted Scan操作符。Log RowScan是一個神祕的資料訪問操作符(從log中讀取資料而不是從資料表中讀取)。

    在很多文獻、文章中還會看到範圍掃描(range scan),這意味著一個查詢操作符快速定位一個基於鍵值的行然後從當前位置繼續向前迴圈遍歷行,有時候止於特定的第二個鍵值。查詢操作基於開始和結束的鍵定義進行掃描,因此叫做範圍掃描。

    回到執行計劃,當查詢樹根節點對操作符呼叫next()方法時,會逐級呼叫其子操作符直到到達資料訪問操作符為止。這些資料訪問操作符通過讀取第一條符合要求的實際資料並返回來實現next()方法。然後記錄位置之後,接下來再次呼叫next()方法讀取下一行並返回,直到全部讀取完畢。資料訪問操作符沒有更多的子操作符,它們就位於查詢樹的葉子端(圖形計劃的最右端)。在資料訪問操作符的上級通常是實現某些功能的操作符,如過濾(filter)、表關聯(join)、排序(sort)、聚合(computing aggregate)等。


總結

    簡單來說,對於各種操作符可以歸納以下行為:

  • 掃描操作讀取所有資料。
  • 查詢操作讀取最小所需資料。
  • 堆只支援掃描和書籤查詢(RID查詢)。
  • B-Tree結構僅在索引鍵最左列被指定時才進行查詢操作。