2013-03-15 103 views
5

爲什麼是SQL Server 2008 R2(版本10.50.2806.0)查詢頂級屬性更快

SELECT 
     MAX(AtDate1), 
     MIN(AtDate2) 
    FROM 
    (
     SELECT TOP 1000000000000 
      at.Date1 AS AtDate1, 
      at.Date2 AS AtDate2 
     FROM 
      dbo.tab1 a 
     INNER JOIN 
      dbo.tab2 at 
     ON 
      a.id = at.RootId 
     AND CAST(GETDATE() AS DATE) BETWEEN at.Date1 AND at.Date2 
     WHERE 
      a.Number = 223889 
    )B 

然後

SELECT 
     MAX(AtDate1), 
     MIN(AtDate2) 
    FROM 
    (
     SELECT 
      at.Date1 AS AtDate1, 
      at.Date2 AS AtDate2 
     FROM 
      dbo.tab1 a 
     INNER JOIN 
      dbo.tab2 at 
     ON 
      a.id = at.RootId 
     AND CAST(GETDATE() AS DATE) BETWEEN at.Date1 AND at.Date2 
     WHERE 
      a.Number = 223889 
    )B 

此查詢速度更快?

具有TOP屬性的第二條語句速度提高了六倍。

內部子查詢的count(*)是9280行。

我可以使用HINT聲明SQL Server優化器是正確的嗎? execution plan

+0

您必須查看執行計劃才能確定。它有可能是在採用TOP比沒有采用更有效的路徑。 – Khan 2013-03-15 14:45:53

+2

這可能是由優化器問題引起的。你能否提供兩種查詢的執行計劃? – 2013-03-15 14:46:53

+3

提供執行計劃的最佳方式是在SSMS中運行它們,並啓用「查詢 - >包括實際執行計劃」選項,然後將XML版本上傳到像pastebin這樣的站點。請參閱[如何向某人提供執行計劃以供分析?](http://meta.dba.stackexchange.com/questions/796/how-do-i-provide-an-execution-plan-to-someone-爲分析)更多。 – 2013-03-15 15:06:51

回答

3

我看你現在已經發布the plans。只是運氣的平局。

您的實際查詢是16表連接。

SELECT max(atDate1) AS AtDate1, 
     min(atDate2) AS AtDate2, 
     max(vtDate1) AS vtDate1, 
     min(vtDate2) AS vtDate2, 
     max(bgtDate1) AS bgtDate1, 
     min(bgtDate2) AS bgtDate2, 
     max(lftDate1) AS lftDate1, 
     min(lftDate2) AS lftDate2, 
     max(lgtDate1) AS lgtDate1, 
     min(lgtDate2) AS lgtDate2, 
     max(bltDate1) AS bltDate1, 
     min(bltDate2) AS bltDate2 
FROM (SELECT TOP 100000 at.Date1 AS atDate1, 
          at.Date2 AS atDate2, 
          vt.Date1 AS vtDate1, 
          vt.Date2 AS vtDate2, 
          bgt.Date1 AS bgtDate1, 
          bgt.Date2 AS bgtDate2, 
          lft.Date1 AS lftDate1, 
          lft.Date2 AS lftDate2, 
          lgt.Date1 AS lgtDate1, 
          lgt.Date2 AS lgtDate2, 
          blt.Date1 AS bltDate1, 
          blt.Date2 AS bltDate2 
     FROM dbo.Tab1 a 
       INNER JOIN dbo.Tab2 at 
       ON a.id = at.Tab1Id 
        AND cast(Getdate() AS DATE) BETWEEN at.Date1 AND at.Date2 
       INNER JOIN dbo.Tab5 v 
       ON v.Tab1Id = a.Id 
       INNER JOIN dbo.Tab16 g 
       ON g.Tab5Id = v.Id 
       INNER JOIN dbo.Tab3 vt 
       ON v.id = vt.Tab5Id 
        AND cast(Getdate() AS DATE) BETWEEN vt.Date1 AND vt.Date2 
       LEFT OUTER JOIN dbo.Tab4 vk 
       ON v.id = vk.Tab5Id 
       LEFT OUTER JOIN dbo.VerkaufsTab3 vkt 
       ON vk.id = vkt.Tab4Id 
       LEFT OUTER JOIN dbo.Plu p 
       ON p.Tab4Id = vk.Id 
       LEFT OUTER JOIN dbo.Tab15 bg 
       ON bg.Tab5Id = v.Id 
       LEFT OUTER JOIN dbo.Tab7 bgt 
       ON bgt.Tab15Id = bg.Id 
        AND cast(Getdate() AS DATE) BETWEEN bgt.Date1 AND bgt.Date2 
       LEFT OUTER JOIN dbo.Tab11 b 
       ON b.Tab15Id = bg.Id 
       LEFT OUTER JOIN dbo.Tab14 lf 
       ON lf.Id = b.Id 
       LEFT OUTER JOIN dbo.Tab8 lft 
       ON lft.Tab14Id = lf.Id 
        AND cast(Getdate() AS DATE) BETWEEN lft.Date1 AND lft.Date2 
       LEFT OUTER JOIN dbo.Tab13 lg 
       ON lg.Id = b.Id 
       LEFT OUTER JOIN dbo.Tab9 lgt 
       ON lgt.Tab13Id = lg.Id 
        AND cast(Getdate() AS DATE) BETWEEN lgt.Date1 AND lgt.Date2 
       LEFT OUTER JOIN dbo.Tab10 bl 
       ON bl.Tab11Id = b.Id 
       LEFT OUTER JOIN dbo.Tab6 blt 
       ON blt.Tab10Id = bl.Id 
        AND cast(Getdate() AS DATE) BETWEEN blt.Date1 AND blt.Date2 
     WHERE a.Nummer = 223889) B 

在這兩個好和壞計劃執行計劃顯示爲「超時」,「爲語句優化的提前終止原因」。

這兩個計劃有不同的連接順序。

索引查找不滿足的計劃中的唯一連接是Tab9。這有63,926行。

執行計劃中缺少的索引詳細信息建議您創建以下索引。

CREATE NONCLUSTERED INDEX [miising_index] 
ON [dbo].[Tab9] ([Date1],[Date2]) 
INCLUDE ([Tab13Id]) 

壞計劃的問題的一部分,可以清楚地看到在SQL哨兵方案資源管理器

Bad Plan

SQL Server的估計,從以前的連接進入的連接上1.349174行將返回Tab9。因此嵌套循環連接的代價就好像它需要在內表上執行1.349174次掃描一樣。

事實上,2,600行進入該連接,這意味着它執行2,600次全掃描Tab9(2,600 * 63,926 = 164,569,600行。)

恰好如此,在良好的計劃中,進入連接的估計行數爲2.74319。這仍然錯誤三個數量級,但稍微增加的估計意味着SQL Server支持散列連接。哈希連接少了點一次通過Tab9

Good Plan

我第一次嘗試在Tab9加入缺失指數。

此外/相反,你可以嘗試更新所涉及的所有表的統計數據(尤其是那些有日期謂詞如Tab2Tab3Tab7Tab8Tab6),看看是否能在某種程度上對糾正估計與實際行之間的巨大差異計劃的左邊。

同樣將查詢分解爲更小的部分並將這些查詢轉化爲具有適當索引的臨時表可能會有所幫助。 SQL Server然後可以使用這些部分結果的統計信息來爲計劃中稍後的連接做出更好的決策。

只有作爲最後的手段,我會考慮使用查詢提示嘗試強制使用散列連接的計劃。您的選擇可以是USE PLAN提示,在這種情況下,您可以完全確定所需的計劃,包括所有加入類型和訂單,或者通過陳述LEFT OUTER HASH JOIN tab9 ...。第二個選項也具有修復計劃中所有連接訂單的副作用。兩者都意味着SQL Server將受到嚴重限制,因爲它能夠根據數據分佈的變化調整計劃。

1

很難回答不知道表的大小和結構,也無法看到整個執行計劃。但是這兩個計劃的區別在於「top n」查詢的哈希匹配連接與另一個計劃的嵌套循環連接。 哈希匹配是非常耗費資源的連接,因爲服務器必須準備哈希存儲桶才能使用它。但對於大型表格,它變得更加有效,而嵌套循環將一個表格中的每一行與另一個表格中的每一行進行比較,這對於小型表格非常適用,因爲不需要這樣的準備。 我認爲通過在子查詢中選擇TOP 1000000000000行,可以爲優化器提供一個提示,即您正在子查詢將生成大量數據,因此它使用哈希匹配。但實際上輸出很小,因此嵌套循環效果更好。 我剛剛說的是基於信息碎片,所以請有心批評我的答案;)。

+0

這是查詢的執行計劃 http://www.dateiupload.net/download.php?文件= 0875b65fb14d01c90b48c5fd146a36e3 – JJANSSEN 2013-03-17 15:56:28

+0

感謝您的答案。我怎麼能給優化器一個提示使用散列連接,所以我可以刪除頂部的屬性 – JJANSSEN 2013-03-17 16:31:26