Sql-Server

執行計劃百分比加起來不是 100%

  • February 11, 2019

我指的是 SQL Server 查詢執行計劃來獲取查詢成本,然後通過查看計劃來優化所需的東西。

但單個查詢成本加起來超過 100%。

這是我的查詢:

DECLARE @date SMALLDATETIME

SELECT Reffd AS NAME
   ,(
       SELECT (
               (
                   SELECT count(*)
                   FROM [cal_reg].[dbo].[customer]
                   WHERE upper(Reffd) = upper(main.reffd)
                       AND cast(DATE AS SMALLDATETIME) = @date
                   ) + (
                   SELECT count(*)
                   FROM [cal_reg].[dbo].[rep]
                   WHERE upper(Reffd) = upper(main.Reffd)
                       AND cast(DATE AS SMALLDATETIME) = @date
                   )
               )
       ) AS Completed
   ,(
       SELECT (
               (
                   SELECT count(*)
                   FROM [cal_reg].[dbo].[customer]
                   WHERE upper([call Attnd]) = upper(main.[Reffd])
                       AND cast(DATE AS SMALLDATETIME) = @date
                   ) + (
                   SELECT count(*)
                   FROM [cal_reg].[dbo].[rep]
                   WHERE upper([Call Attnd]) = upper(main.reffd)
                       AND cast(DATE AS SMALLDATETIME) = @date
                   )
               )
       ) AS Attended
   ,(
       SELECT (
               (
                   SELECT (
                           (
                               SELECT count(*)
                               FROM [cal_reg].[dbo].[customer]
                               WHERE upper(Reffd) = upper(main.reffd)
                                   AND cast(DATE AS SMALLDATETIME) = @date
                               ) + (
                               SELECT count(*)
                               FROM [cal_reg].[dbo].[rep]
                               WHERE upper(Reffd) = upper(main.Reffd)
                                   AND cast(DATE AS SMALLDATETIME) = @date
                               )
                           )
                   )
               ) + (
               SELECT (
                       (
                           SELECT count(*)
                           FROM [cal_reg].[dbo].[customer]
                           WHERE upper([call Attnd]) = upper(main.[Reffd])
                               AND cast(DATE AS SMALLDATETIME) = @date
                           ) + (
                           SELECT count(*)
                           FROM [cal_reg].[dbo].[rep]
                           WHERE upper([Call Attnd]) = upper(main.reffd)
                               AND cast(DATE AS SMALLDATETIME) = @date
                           )
                       )
               )
       ) AS Total
   ,'' AS f6row
   ,'' AS f8row
FROM [cal_reg].[dbo].[customer] AS main
WHERE cast(DATE AS SMALLDATETIME) = @date
   AND upper(reffd) IN (
       SELECT upper(shname)
       FROM common.dbo.Password_table
       )
GROUP BY reffd

為此,我總共得到了 104%,如下所示:

在此處輸入圖像描述 + 在此處輸入圖像描述

我的問題是有可能解決超過 100% 的成本錯誤,還是有其他方法可以告訴我查詢是否有效執行?

執行計劃中操作員成本的總和超過 100% 是一個已知錯誤,並且按設計關閉

Microsoft 於 2010 年 11 月 17 日下午 5:28 發布

感謝您花時間送出此觀察和簡單的複制。您觀察到的奇怪的成本百分比值是查詢計劃的特定結構的產物,這有點令人困惑,但最終確實有意義。它們不會以任何方式對查詢的執行產生不利影響。

連接運算符有兩個孩子 - 表掃描。但是,伺服器希望不必執行第二次表掃描。這是因為它希望從第一個表掃描中找到滿足查詢的“存在”部分的行。因此,在計算以連接為根的子樹的總成本時,它不包括第二次表掃描的成本。然而,它仍然估計並報告第二次表掃描的成本,管理工具將其計算為總查詢成本的百分比,就好像它將被執行一樣。

當然,在這種情況下,有必要執行第二次表掃描,因為第一次是空的。但是,引擎在保守的假設下執行,即始終至少有一行(可能僅在編譯查詢後才添加)。

坎貝爾

SQL 開發

Aaron Bertrand 送出了一個類似的錯誤 - SSMS:執行計劃有時超過 100%

Microsoft 於 2008 年 5 月 28 日上午 11:58 發布

再次感謝您引起我們的注意。這種異常出現在“行目標”和連接運算符存在的情況下。行目標是指何時不需要子樹(可能是整個查詢)返回所有可能的行。這最常發生在查詢具有“top”子句時,儘管還有其他原因。出現異常是因為我們不希望執行 Concatenation 的第二個孩子(因為我們希望第一個孩子提供所有必需的行)。假設他們返回單行,這些額外的孩子需要付出代價。唯一的選擇是給他們 0 成本,這將修復異常但可能會造成其他混亂,並導致優化器不關心計劃 - 我們不想這樣做以防萬一他們被執行。

坎貝爾弗雷澤,SQL 開發。

如果您想了解計劃成本核算的工作原理,Paul White 將在此處盡其所能進行解釋。

來自查詢處理器團隊 -這個成本是多少?

提高性能的一般準則 -

  • 有適當的索引和最新的統計數據。
  • 僅獲取所需的數據以及相關列。
  • 擁有適當的 schema.table 和適當的索引和數據類型
  • 使用統計時間、IO 在您進行更改之前和之後來衡量增益。
  • 從本網站的專家那裡獲得幫助/指導 :-)

這就是我使用SQL Sentry 的免費計劃資源管理器的原因

我不會擔心 100%

大數字就是大數字

很多重複,所以開始優化一個

這只是您查詢的一個子集

DECLARE @date SMALLDATETIME

SELECT Reffd AS NAME
    , ( SELECT (  ( SELECT count(*)
                    FROM [cal_reg].[dbo].[customer]
                    WHERE upper(Reffd) = upper(main.reffd)
                    AND cast(DATE AS SMALLDATETIME) = @date
                  ) 
                  + 
                  ( SELECT count(*)
                    FROM [cal_reg].[dbo].[rep]
                    WHERE upper(Reffd) = upper(main.Reffd)
                      AND cast(DATE AS SMALLDATETIME) = @date
                  )
               )
      ) AS Completed
FROM [cal_reg].[dbo].[customer] AS main
WHERE cast(main.DATE AS SMALLDATETIME) = @date
AND upper(main.reffd) IN ( SELECT upper(shname)
                          FROM common.dbo.Password_table )
GROUP BY main.reffd

使用不區分大小寫的排序規則

如果這是一個字元欄位,完整的 DATETIME 將消除一些成本

,那麼這是一個問題,您應該修復數據

DECLARE @date DATETIME

SELECT Reffd AS NAME
    , ( SELECT (  ( SELECT count(*)
                    FROM [cal_reg].[dbo].[customer]
                    WHERE Reffd = main.reffd
                    AND DATE = @date
                  ) 
                  + 
                  ( SELECT count(*)
                    FROM [cal_reg].[dbo].[rep]
                    WHERE Reffd = main.Reffd
                    AND DATE = @date
                  )
               )
      ) AS Completed
FROM [cal_reg].[dbo].[customer] AS main 
JOIN common.dbo.Password_table pw
      on pw.shname = main.reffd
WHERE main.DATE = @date
GROUP BY main.reffd

這可以分解為連接

DECLARE @date DATETIME

SELECT Reffd AS NAME
    , ( count(cusR.Reffd) + count(repR.Reffd) ) as AS Completed
    , ( count(cusA.[call Attnd]) + count(repA.[call Attnd]) ) as AS Attended
    , ( count(cusR.Reffd) + count(repR.Reffd) + count(cusA.[call Attnd]) + count(repA.[call Attnd]) ) as AS Total
FROM [cal_reg].[dbo].[customer] AS main 
JOIN common.dbo.Password_table pw
      on pw.shname = main.reffd
     and main.DATE = @date
left join [cal_reg].[dbo].[customer] [cusR]
      on cusR.Reffd = main.reffd
     and cusR.DATE = main.DATE
left join [cal_reg].[dbo].[rep]   as [repR]
      on repR.Reffd = main.Reffd
     and repR.DATE = main.DATE
left join [cal_reg].[dbo].[customer] [cusA]
      on cusA.[call Attnd] = main.reffd
     and cusA.DATE = main.DATE
left join [cal_reg].[dbo].[rep]   as [repA]
      on repA.[call Attnd] = main.Reffd
     and repA.DATE = main.DATE
GROUP BY main.reffd

如果您在所有 Reffd 和 Date 上都有索引,那麼這應該會快速吸煙

那些循環正在殺死它,

希望這將擺脫其中一些循環

這就像一個刀具廣告 - 但等等還有更多

SELECT Reffd AS NAME
    , ( count(cus.Reffd) + count(rep.Reffd) ) as AS Completed
    , ( count(cus.[call Attnd]) + count(rep.[call Attnd]) ) as AS Attended
    , ( count(cus.Reffd) + count(rep.Reffd) + count(cus.[call Attnd]) + count(rep.[call Attnd]) ) as AS Total
FROM [cal_reg].[dbo].[customer] AS main 
JOIN common.dbo.Password_table pw
      on pw.shname = main.reffd
     and main.DATE = @date
left join [cal_reg].[dbo].[customer] [cus]
      on main.reffd in (cus.Reffd, cus.[call Attnd])
     and cus.DATE = main.DATE
left join [cal_reg].[dbo].[rep]   as [rep]
      on main.Reffd in (rep.Reffd, rep.[call Attnd])
     and rep.DATE = main.DATE
GROUP BY main.reffd

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