SQL Server中TOP子句可能致使的問題以及解決辦法

簡介

     在SQL Server中,針對複雜查詢使用TOP子句可能會出現對性能的影響,這種影響多是好的影響,也多是壞的影響,針對不一樣的狀況有不一樣的可能性。算法

     關係數據庫中SQL語句只是一個抽象的概念,不包含任何實現。不少元數據都會影響執行計劃的生成,SQL語句自己並不做爲生成執行計劃所參考的元數據(提示除外),但TOP關鍵字倒是直接影響執行計劃的一個關鍵字,所以在某些狀況下使用TOP會致使性能受到影響,下面咱們來看集中不一樣的狀況。數據庫

 

單表狀況

    對於單表查詢(這裏的所說的單表指的是不包含視圖、表值函數的物理單表)來講,存在TOP基本不會對性能產生影響,若是在SQL Server中加入了TOP,那麼TOP自己能夠看做是一個查詢提示,意味着告訴優化器「返回結果只有N行」。咱們看一個簡單的例子,如圖1所示:app

image

圖1.指定TOP關鍵字的單表執行計劃函數

 

    由圖1執行計劃對比能夠看出,對於有索引支撐的單表查詢來講,使用TOP子句每每能夠提高性能,此時TOP N的行數的N則提示查詢優化器該查詢返回N行,而不是使用統計信息中的數據分佈,此時TOP N對於查詢優化器來講是合理的。oop

    但有些時候Grant Memory(每次執行計劃生成時會預估所需的內存,若是預估內存小於執行內存,則會spill to tempdb,對性能產生很是大的影響,因爲每個版本預估內存的公式變化極大,所以不在此詳細解釋了)不許會產生很是高的性能影響。在開始談這點,以前,咱們先談兩個操做符:性能

Sort

    Sort操做符是很是通用的排序操做符,在執行計劃中可能會出如今多個地方,好比Merge Join以前,因爲Order By致使的等。該算法很是通用,能夠對很是大的結果集進行排序,該操做符是阻塞式(意味着排序結束以前數據沒法流動到下一個操做符),而且須要大量內存和CPU資源。該操做符還有一個問題是當Grant Memory不足時,須要TempDB輔助完成排序,所以有極大的性能開銷。測試

Top N Sort

    TOP N Sort是適應小場景,專門針對少許查詢的排序算法。對於只選擇幾條數據來講,對於整個結果集進行排序成本過於高昂,所以TOP N的算法是首先取第一條數據,與其餘數據進行對比,看是否最大(或最小),再取第二條數據對比,依次類推,直到找到前N條數據。該算法若是行數較小,則相比SORT操做符性能提高明顯,但若是N值過大,則因爲下述緣由該算法不合適:優化

1.該算法不支持spill to tempdb,致使沒法承載太大的結果集。spa

2.該算法須要遍歷N次,若是N過大,則成本太高。3d

 

    對於SQL Server來講,這個N是否過大的閾值是100。下面咱們來看一個例子,測試數據和代碼如代碼清單1所示。

CREATE TABLE TestTop
(id INT,sortkey INT,SOMEvalue CHAR(1000))
 
  DECLARE @i INT =1
  WHILE @i<300000
  BEGIN
  INSERT INTO TestTop VALUES(@i,@i,'a')
  SET @i=@i+1
  END
  
  CREATE CLUSTERED INDEX PK_id ON TestTop(id)
  --test 1
  SELECT TOP(100) * FROM TestTop
  ORDER BY sortkey
  --test 2
  SELECT TOP(101) * FROM TestTop
  ORDER BY sortkey

代碼清單1.測試數據與測試代碼

 

    第一個測試爲TOP 100,正好使用TOP N Sort的算法,第二個測試爲TOP 101,只能使用普通Sort的算法,如圖2所示。

image

圖2.TOP 101的SORT須要更多內存,從而致使內存授予不足spill to tempdb

 

    咱們再來看執行時間,因爲spill to tempdb的存在,那麼執行時間如圖3所示。

image

圖3.相差很是大的執行時間

    從圖3能夠看出,執行時間相差很是大。

   所以對於TOP的使用來講,儘可能使用TOP 100之內的數值。

 

多表狀況

    因爲TOP語句帶有對優化器基數估計的提示功能,所以多表查詢時在極端狀況下可能致使行數低估從而影響性能。

    好比下面如圖4的示例查詢

image

圖4.使用TOP 1的表接連查詢

 

    在這種狀況下,因爲TOP1的存在使得查詢優化器使用1做爲估計行數,與實際的行數差別巨大,所以對於這種狀況,使用TOP反而可能致使成本更高(雖然咱們看到圖4中估計的是0%對比100%,但實際差別巨大),更高的緣由不只僅是優化器估計爲1,由於Loop Join只要發現1條就能夠馬上結束,但上面例子中因爲過濾條件選擇性太低,致使找到第一條數據的隨機查找過多(loop join內表循環是隨機IO),成本如圖5所示。

image

圖5.使用TOP反而致使性能降低

 

    根本緣由是因爲估計行數只有1行,大部分狀況下這一行

    對於上面這種狀況來講,咱們一般能夠有下面集中解決辦法:

1.使用提示,因爲咱們知道這是因爲實際行數遠大於估計行數致使,所以咱們能夠嘗試使用hash join,forcescan等提示。

2.增長where條件,使得返回行數具備更高的選擇性。

3.不使用TOP1,而使用TOP 10以上的數字,讓估計行數變大,好比圖5中的查詢咱們由TOP1 變爲TOP10,那麼執行計劃則變爲如圖6所示。

image

圖6.TOP 10的執行計劃

 

    這是因爲當行數少時,LOOP JOIN能夠更快返回有限的行數,至關於對錶加了FAST N提示,但行數增多時,優化器更傾向使用MERGE或者HASH完成操做,在上面返回行極多(選擇性低)的極端狀況下,會擁有更好的性能,結果如圖7所示。

image

圖7.特殊狀況下TOP10相比TOP1有更好性能。

 

    所以結合單表的例子,推薦使用TOP關鍵字時,數字在10到100之間。

 

小結

    本文介紹了TOP關鍵字在單表和多表條件下可能對執行計劃產生的影響,進而影響了查詢計劃。TOP影響執行計劃主要是下面兩個方面:

  • 內存授予
  • 估計行數

    所以在特殊狀況下調優TOP語句時,能夠根據實際狀況考慮本文的建議。

相關文章
相關標籤/搜索