Query-Performance

SQL Server 突然使用索引掃描而不是搜尋

  • September 28, 2021

我們有一個每天執行的儲存過程。在其中一個子查詢(執行計劃中的查詢 20)中,SQL Server 一直使用索引查找直到 2021/09/24。但是突然之間,當查詢在 2021/09/25 執行時,SQL Server 在同一步驟開始使用索引掃描。

以下是 2021/09/24 的計劃,它正在執行搜尋

2021/09/24 查詢計劃 求2021/09/24營業

以下是 SQL Server 執行索引掃描的 2021/09/25 計劃

2021/09/25 查詢計劃 2021/09/25掃描操作

EMAIL_SENDS_CCMP_LTD 表是一個相當大的表,下面是表的空間使用數據

EMAIL_SENDS_CCMP_LTD統計

以下是上面突出顯示的儲存過程中的查詢 -

insert into  TALBOTS_BASE.dbo.EMAIL_ACTIVITIES
(EMAILTYPE,INTSOURCE,EMAIL,ACCTNO,FNAME,LNAME,EMAILDATE,DNEFLAG,SOURCE_CD,CREATE_ID,EMAILPREF,HASH,FILENAME,SEQ,FILEDATE,MODDATE,IPADDRESS,HAV_EMAILDATE)
SELECT 
     'OPEN' AS EMAILTYPE
     ,'CCMP' AS INTSOURCE 
     , a.[P_email] AS EMAIL
     ,'' AS ACCTNO
     ,'' AS [FNAME]
     ,'' AS [LNAME]
     ,CASE WHEN ISNULL(c.Subchannel,'')<>'HWW' 
      THEN
           CASE WHEN ISDATE([click_time])=1 THEN CAST([click_time] AS DATE) ELSE NULL END
     ELSE NULL
     END AS EMAILDATE
     ,'' as DNEFLAG
     ,'' AS SOURCE_CD
     ,'' AS CREATE_ID
     ,null as EMAIL_CONTACT_PREFERENCE
     ,a.HASH
     ,a.FILENAME
     ,a.SEQ
     ,a.FILEDATE
     ,a.MODDATE
     ,a.ip_address
     ,CASE WHEN c.Subchannel='HWW' 
      THEN
           CASE WHEN ISDATE([click_time])=1 THEN CAST([click_time] AS DATE) ELSE NULL END--HAVEN
     ELSE NULL
     END AS HAV_EMAILDATE
FROM [TALBOTS_RAW].[dbo].[EMAIL_OPENS_CCMP_LTD] a
left join #activitiesfiles b 
on a.FILENAME = b.FILENAME 
LEFT JOIN [TALBOTS_RAW].[dbo].[EMAIL_SENDS_CCMP_LTD] c 
ON a.p_email = c.p_email
AND a.msg_id = c.msg_id  
WHERE b.FILENAME is null

EMAIL_SENDS_CCMP_LTD 表上有一個非聚集索引,該表在 p_email(VARCHAR) 和 msg_id(VARCHAR) 列上,包含列作為 Subchannel(VARCHAR)。

我的問題是 SQL Server 決定更改查詢計劃的參數是什麼,有沒有辦法允許 SQL Server 使用搜尋而不是掃描。

粘貼實際計劃

2021/09/24 查詢計劃

2021/09/25 查詢計劃

過濾器

您的計劃改變的原因是因為有多少行將通過過濾器運算符的基數估計發生了很大變化。

堅果

一般來說,這是一件很難估計的事情——您正在使用左連接來查找不存在的行#activitiesfiles——這通常使用 NOT EXISTS 更好地表達

FROM [TALBOTS_RAW].[dbo].[EMAIL_OPENS_CCMP_LTD] a
LEFT JOIN [TALBOTS_RAW].[dbo].[EMAIL_SENDS_CCMP_LTD] c 
   ON  a.p_email = c.p_email
   AND a.msg_id = c.msg_id  
WHERE NOT EXISTS
     (
         SELECT
             1/0
         FROM #activitiesfiles b 
         WHERE a.FILENAME = b.FILENAME 
     );

看起來您在這裡並沒有讓自己變得更輕鬆,因為您的電子郵件打開表似乎沒有有用的索引。

堅果

我意識到這不是您遇到問題的計劃的一部分,但值得注意的是,因為關注的是選擇的連接算法。

您可能會獲得一個更好的總體計劃,filename, msg_id, p_email其中包含您從中選擇的列的索引EMAIL_OPENS_CCMP_LTD

解決這個問題有點困難,因為您的列並非都以您為表提供的別名作為前綴,所以我將把它留給您。

最後,您至少應該了解 SQL Server 如何在查詢計劃中記憶體臨時對象和統計資訊,Paul White 在這三篇文章中對此進行了解釋:

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