Sql-Server

慢查詢 - 估計行和實際行之間的巨大差異

  • December 17, 2016

在我的工作中,我們遇到了搜尋查詢問題。

如果我不包含查找Table_39(請參閱下面的查詢),則執行查詢需要 0 秒。如果我包括查找 ( ..AND (Not Exists(Select 1 From Table_39 ll ..),則需要 4 分 57 秒。

從執行計劃中我可以看到預期行數和實際行數之間存在巨大差異,特別是在索引中Table_39(估計為 62.6 與 10,956,165),所以我嘗試執行UPDATE STATISTICS WITH FULLSCAN,但沒有任何區別。

對於如何提高包含查找的查詢的性能,我將不勝感激!

詢問:

select [Table_2].Gid
 into #Table_1
 from [Table_2]
where [Table_2].Gid_Line in ('{31445a8f-900b-4d64-b72f-4e2ac10fd6a7}')
union
select '{31445a8f-900b-4d64-b72f-4e2ac10fd6a7}' as Gid

create unique nonclustered index temp_Table1 on #Table_1 (Gid)
go

select top 500 Table_9.Id
, Table_9.Gid
, Table_9.name
, Table_9.TimeEnter
, Table_9.Prio
, Table_9.Direction
, Table_9.status
, Table_9.CreaterId
, Table_9.Subject
, Table_9.BodyType
, Table_9.Attach
, Table_9.FromAddr
, Table_9.ToAddr
, Table_9.Gid_LineSet
, Table_9.xml
from Table_9
where Table_9.Gid_LineSet in (
   select Gid
     from #Table_1
     ) 
 and not exists (
  select 1
  from Table_39 ll
  where ll.Id_Obj_To      = Table_9.Id 
   and ll.Id_ObjType_To   = 5 
   and ll.Id_ObjType_From = 3 
   and ll.Id_Obj_From in (
       9602, 10661, 10857, 10858, 10859, 68823
     , 68824, 68825, 68826, 68827, 68828, 68829
     , 68830, 68831, 68832, 68833, 68834, 372513
     )
   )
order by Table_9.Id desc

drop table #Table_1

慢查詢的執行計劃(帶查找):https ://www.dropbox.com/s/rc1i6vvdwwc5hzh/long%20query_Cleaned.sqlplan?dl=0

快速查詢的執行計劃(無查找): https ://www.dropbox.com/s/bjafn5tiy3uepul/short%20query_Cleaned.sqlplan?dl=0

行目標

估計的問題很可能是由於TOP (500). 看:

TOP 如何(以及為什麼)影響執行計劃?

TOP如果您發現沒有或通過添加OPTION (QUERYTRACEON 4138)到查詢中的估計要好得多,那將證實該假設。

跟踪標誌 4138 記錄在 KB 2667211 中:

如果查詢優化器在 SQL Server 2008 R2 或 SQL Server 2012 中使用 Top 運算符,則查詢可能需要很長時間才能執行

您還應該使用跟踪標誌 4199 啟用優化器修復。

索引

考慮在表 39 上創建索引,鍵入:

Id_Obj_To, Id_ObjType_To, Id_ObjType_From, Id_Obj_From

確保Id_Obj_From具有合適的數據類型(例如max類型)。

預測排序

NOT EXISTS優化器在您的 SQL Server 版本中不能很好地重新排序子句。如果您希望NOT EXISTS子句比謂詞更具選擇性,請在查詢部分Gid_LineSet重新排序這兩個子句。WHERE

我還沒有看到執行計劃,連結不起作用。

當您執行 where not in Table_39 時,它將返回所有行。嘗試將 Table_39 中的數據放入基於“And ll.Id_Obj_From in(9602,10661,10857,10858,10859,68823,68824,68825,68826,68827,68828,68829,68830,68831,68832, 68833,68834,372513)"

這將是一個較小的表,可以駐留在記憶體中,而不是寫入 tempdb。只獲取您需要的列並將它們放入臨時表中。

例如,如果它們是 INT 並且將駐留在記憶體中,我可以將 1000 行放入臨時表中。但是,如果我將每行 20 Meg 的 2 行 XML 放入一個臨時表中,它將被寫入 tempdb。這是一個誇張的範例,但關鍵是臨時表是駐留在記憶體中還是寫入 tempdb 取決於數據的大小。

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