一、高級掃描使用舉例
通常情況下在數據查詢的時候,數據庫會利用索引或者通過全表掃描來查找數據。但是如果需要的數據在數據庫中存儲不連續或者需要查找的記錄比較多時,此時索引的效果就會大打折扣。在這種情況下,數據庫查詢優化器可能會采用全表掃描來代替索引。但是眾所周知,全表掃描的效率是比較低下的。為此在SQL Server數據庫的企業版中,提出了一個高級掃描的處理方式。簡單的說,高級掃描可以讓多項查詢任務共享完全表掃描。筆者先給大家舉一個例子,然後再跟大家談談隱藏在其背後的秘密。
如在上圖中,一個表中的記錄比較多有40000頁。用戶甲需要查詢這個表中的記錄,假設其采用了全表掃描。當數據庫查詢到20000頁的時候,用戶乙也需要這個表中的數據,那麼又觸發了一個全表掃描。此時如果沒有采用高級掃描技術的話,則用戶乙的SQL語句必須要等到用戶甲的執行完畢後才會執行。而如果采用了高級掃描技術的話,則數據庫在從20000頁開始的全表掃描中,會把掃描的結果分成兩個副本,分別給用戶甲與乙。然後當第30000頁的時候,用戶丙也參與進來了。同理數據庫引擎會把從30000頁開始的掃描結果分為三個副本,分別給三個用戶。當整個表掃描完成之後,數據庫引擎就會把結果返回給用戶甲。然後再從頭開始掃描,當掃描到20000頁的時候,就會把上次掃描的20000頁到400000頁的結果合並起來然後返回給用戶乙。掃描到300000頁的時候就會把與上次掃描到的結果合並起來返回給用戶丙。
可見如果在不同高級掃描功能的話,則不同用戶在不同時刻的查詢請求,可能需要對某個表進行全表掃描三次。而在上面這個案例中,則知需要對這個表掃描2次都不到。為此當多個對同一個表進行全表掃描時,高級掃描工具可以明顯提高數據庫的運行性能。
二、高級掃描實現的秘密
可見高級掃描其主要就是通過共享全表掃描技術來實現的。也就是說,當SQL語句的執行計劃需要掃描表中的數據頁(即全表掃描),並且數據庫引擎檢測到其他查詢執行計劃正在掃描這個表中的時候(如上例中用戶乙、丙參與進來),則數據庫引擎就會在第二個掃描的當前位置將第二個掃描插入到第一個掃描中(此時數據庫引擎會會把掃描的結果產生一個副本)。數據庫引起會一次讀取一頁,並加每一頁的行傳遞給多個執行計劃,一直到當前掃描結束。
此時,第一個掃描(用戶甲)已經完全結束,數據庫引擎就會把掃描的結果傳遞給用戶甲的進程。但是此時數據庫乙還不能夠把結果返回給用戶乙,因為在用戶甲開始查詢到用戶乙遞交SQL語句中間,可能會有用戶對前面幾頁的數據進行修改。為此數據庫引擎需要對先前的頁進行重新掃描,以防止數據的誤讀。為此第二個查詢計劃必須發起第二個全表掃描,檢索第二個執行計劃加入第一次掃描正在進行的掃描之前讀取的數據頁。即第二個執行計劃的掃描將繞回到第一個數據頁,並從這裡開始掃描,直到其加入到第一個掃描時的位置。然後數據庫引擎會把掃描到的結果返回給第二個查詢計劃,依次類推。在實際工作中,可以按這種方式組合任意數量的掃描。其實這種掃描很想走馬燈,為此我們又把高級掃描戲稱為全表掃描。可見在這種情況下,如果多個用戶在一次全表掃描的過程中查詢同一個表,則可以減少全表掃描的次數。如果在沒有高級掃描的情況下,像上面的用戶甲、乙、丙都必須要爭用緩沖區空間並因此導致硬盤或者內存的爭用等等。然後數據庫引擎會分別為每一個用戶讀取依次相同的頁,而不是每次讀取的結果有多個用戶共享。顯然跟高級掃描比起來,這種處理方式其效率會低很多。
三、高級掃描的弊端與解決方式
雖然高級掃描會提高數據庫的查詢性能,但是這種處理機制也會有一個弊端,即會導致查詢結果記錄順序的混亂。如上面這個例子中,如果三個用戶采用的都是同一個查詢語句的話,則其最後返回的結果雖然記錄的內容是相同的,但是顯示的記錄順序是不同的(假設沒有采用排序語句)。這可能會給用戶一種誤解,以為各自查到的是不同的內容。為什麼會產生這種情況呢?為了說們這個問題的原因,筆者就對表中的內容進行簡化。假設某一張表中有三條記錄,序號分別為1、2、3。
現在用戶甲需要查詢這個表中的內容,進行了一次全表掃描。當第一條記錄查詢完畢之後,用戶乙也需要查詢這個表。從這次開始的後續查詢中,數據庫引擎會把結果同時發送給用戶甲與乙兩個查詢計劃。也就是說,用戶乙此時掃描的第一個結果是序號為2的記錄。然後用戶丙又插了進來,那麼這個時候數據庫引擎返回給用戶丙執行計劃的第一條記錄就是序號為3的記錄了。第一次掃描完畢後,再重新進行第二次掃描,然後把序號為1的記錄返回給用戶乙。最後用戶甲顯示的記錄順序為1、2、3;而用戶乙顯示的記錄順序為2、3、1;用戶丙顯示的記錄順序為3、2、1。當記錄比較少的時候,用戶還可以一目了然的指導查詢結果是相同的,只是順序顛倒了而已。但是如果記錄比較多的情況下,則用戶丙很可能會誤認為其找到的記錄跟甲是不同的。因為順序混亂,所以不能夠清楚的判斷所查找的記錄是否相同。
為此在實際工作中,需要克服這個弊端。最簡單的方式就是采用order by語句對查詢的結果進行掃描。但是眾所周知,對記錄進行排序會增加數據庫額外的開銷,會抵消高級掃描所帶來的性能提升的效果。故通常情況下對於可能需要用到高級掃描的SQL語句,不會采用order by等排序語句,除非用戶非常明確的有這方面的需要,才會把這個語句加入進去。另外需要注意的是,有些匯總語句,如Group By等也會對記錄進行自動排序,這也會增加額外的負擔。但是一般來說,即使是需要對查詢結果進行排序,那麼排序過程中的開銷相比多次全表掃描的開銷來說,還是要小的多。也就是說,在高級掃描後進行排序來解決這個記錄顯示順序不一致的情況,仍然是可行的。
四、影響高級掃描效果的因素
如上的分析中,在一個查詢計劃的執行過程中,如果越多的查詢計劃插入到其中來,那麼這個高級掃描技術的效果就越佳。相反,如果一個查詢計劃完成後,仍然沒有用戶加入到這個查詢計劃中,那麼這個高級掃描的功能就根本沒有發揮出來。此時查詢就只是一個簡單的全表掃描。為此對這個高級掃描的效果,直接跟用戶的參與度相關。如果在一個比較短的時間間隔內,比較多的用戶發起了對一個表的查詢,那麼高級掃描的效果才能夠體現出來。為此數據庫管理員需要知道,並不是在任何時候數據庫系統上實現高級掃描就可以實現比較高的數據庫性能。而是需要跟數據庫的實際應用以及員工的作業有關。
為此企業如果比較多的用戶需要對某張表進行查詢的時候,那麼就需要考慮是否能夠采用高級掃描。如在一個ERP系統中,其產品信息有幾百萬條。有多個用戶需要查詢這個產品信息表中的內容,需要把查票信息導出來以作他用。此時各個部門的用戶如果在前後時間間隔不是很大的情況下,對這個表發起查詢作業。那麼此時就可以利用高級掃描工具來共享掃描對結果,減少全表掃描此時,提高掃描結果。
除了用戶人數之外,還需要注意的是記錄的內容多少也跟這個高級掃描的效果有關。如高紀錄比較到,則這個全表掃描的時間就比較長。而執行計劃長了,則在這個執行計劃的執行過程中參與的用戶可能會越多。那無疑也可以提高高級掃描的效果。此時可以起到一個累加的效果,用戶總的等待時間會隨著參與到這個查詢計劃中來的用戶數量而減少。人數越多,用戶總的等待時間比全表掃描需要花費的時間少的會更多。