Sql-Server

在 SQL Server 上建構執行計劃花費的時間太長

  • November 10, 2020

我有一個 SQL Server 2014 實例 (12.0.2000.8) 和一個相當複雜的 SELECT 語句,大約有 20 個連接。此查詢在 PostgreSQL、Oracle 和其他數據庫上的相同數據集上執行良好,整個執行大約需要 1 分鐘。

但在 SQL Server 上大約需要 40 分鐘。我試圖查看執行計劃並開始等待……我試圖通過從應用程序會話中執行查詢來獲取執行計劃,但沒有執行計劃。

然後我得到了查詢並在SQL Server Management Studio中詢問“顯示估計的執行計劃”,我也開始等待。因此,看起來僅僅建構執行計劃就需要花費太多時間。所有統計資訊都使用“exec sp_updatestats”收集,我在 sys.stats 中檢查了它——一切看起來都很好。所有指標都已到位。

我評論了所有加入並開始一一取消評論,並且

 SET STATISTICS TIME ON

表明每個未註釋的連接都需要更長的時間來解析,例如 13 次連接的時間:

SQL Server parse and compile time:
  CPU time = 32250 ms, elapsed time = 32729 ms.

所以,這絕對是一個解析問題。

select count(*) from sys.index_columns
where object_id in (OBJECT_ID('tables_names'),...')

說有 128 列,當

select * from sys.indexes
where object_id in (OBJECT_ID('tables_names'),...')

返回具有 HEAP、CLUSTERED、NONCLUSTERED 索引的 43 行。

你能推薦看什麼嗎?為什麼解析這麼多?

更新:感謝“打破查詢”和“使用 FORCE ORDER 提示”,但此 SQL 是由我們的應用程序生成的,因此使用應用程序邏輯可能需要付出很多努力,但在一般情況下他們應該是一個很好的解決方案。

第二次更新:應用 SP3 完成了整個工作 - 整個執行查詢花費了不到一秒鐘的時間。性能提高了兩千倍:)

我有一個 SQL Server 2014 (12.0.2000.8)

RTM 版本?我記得某些查詢的編譯持續時間(分鐘)過長。該問題已在 RTM 後修復。我建議您將您的伺服器打更新檔到受支持的更新檔級別 (SP3+)。

我希望優化器花費大部分編譯時間來考慮重新排序許多連接的不同方法。

解決此問題的兩個選項是:

分解查詢

根據您的查詢,一種可能有效的方法是將查詢的關係部分與資訊部分分開。這涉及將查詢分成兩部分,因此每個部分的連接更少(因此優化器探勘的複雜性更低)。

該方法本質上是採用過濾行或以其他方式提供查詢邏輯的內容(在 where 子句、內部連接等中涉及的列)並僅執行該查詢,將其插入臨時表中。

然後在剛剛加入臨時表的單獨查詢中添加其餘的“資訊”或顯示相關內容。

我第一次從 Erik Darling 那裡聽說過這個,這裡有一個很好的例子:資訊與關係

請注意,這主要是為了避免廣泛的結果和索引,但如果您能夠完全消除第一個查詢中的一些連接,它可能對編譯有效。

使用 FORCE ORDER 提示

添加OPTION (FORCE ORDER)到查詢的末尾應該會限制編譯時間,儘管您可能必須嘗試連接的書面順序以獲得合理的執行計劃(這可能會隨著您的數據或模式的變化而隨著時間而改變)。

冒著成為 Erik Darling Data 粉絲的風險,這篇文章與您的情況相關,值得一讀:長時間編譯是否讓您失望?

那篇文章討論了FORCE ORDER解決這個問題的方法(特別是使用計劃指南,因為問題查詢是由 EF 生成的,因此無法輕易在源中添加提示)。

引用自:https://dba.stackexchange.com/questions/279409