我们正在为我们的网站安装一个新论坛(yaf)。其中一个存储过程非常慢 - 实际上它总是在浏览器中超时。如果我在MSSMS中运行它需要将近10分钟才能完成。如果花了这么长时间,有没有办法找出这个查询的哪个部分?
查询:
DECLARE @BoardID int
DECLARE @UserID int
DECLARE @CategoryID int = null
DECLARE @ParentID int = null
SET @BoardID = 1
SET @UserID = 2
select
a.CategoryID,
Category = a.Name,
ForumID = b.ForumID,
Forum = b.Name,
Description,
Topics = [dbo].[yaf_forum_topics](b.ForumID),
Posts = [dbo].[yaf_forum_posts](b.ForumID),
Subforums = [dbo].[yaf_forum_subforums](b.ForumID, @UserID),
LastPosted = t.LastPosted,
LastMessageID = t.LastMessageID,
LastUserID = t.LastUserID,
LastUser = IsNull(t.LastUserName,(select Name from [dbo].[yaf_User] x where x.UserID=t.LastUserID)),
LastTopicID = t.TopicID,
LastTopicName = t.Topic,
b.Flags,
Viewing = (select count(1) from [dbo].[yaf_Active] x JOIN [dbo].[yaf_User] usr ON x.UserID = usr.UserID where x.ForumID=b.ForumID AND usr.IsActiveExcluded = 0),
b.RemoteURL,
x.ReadAccess
from
[dbo].[yaf_Category] a
join [dbo].[yaf_Forum] b on b.CategoryID=a.CategoryID
join [dbo].[yaf_vaccess] x on x.ForumID=b.ForumID
left outer join [dbo].[yaf_Topic] t ON t.TopicID = [dbo].[yaf_forum_lasttopic](b.ForumID,@UserID,b.LastTopicID,b.LastPosted)
where
a.BoardID = @BoardID and
((b.Flags & 2)=0 or x.ReadAccess<>0) and
(@CategoryID is null or a.CategoryID=@CategoryID) and
((@ParentID is null and b.ParentID is null) or b.ParentID=@ParentID) and
x.UserID = @UserID
order by
a.SortOrder,
b.SortOrder
IO统计:
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_Active'. Scan count 14, logical reads 28, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_User'. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_Topic'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_Category'. Scan count 0, logical reads 28, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_Forum'. Scan count 0, logical reads 488, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_UserGroup'. Scan count 231, logical reads 693, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_ForumAccess'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_AccessMask'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'yaf_UserForum'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
客户统计:
Client Execution Time 11:54:01
Query Profile Statistics
Number of INSERT, DELETE and UPDATE statements 0 0.0000
Rows affected by INSERT, DELETE, or UPDATE statements 0 0.0000
Number of SELECT statements 8 8.0000
Rows returned by SELECT statements 19 19.0000
Number of transactions 0 0.0000
Network Statistics
Number of server roundtrips 3 3.0000
TDS packets sent from client 3 3.0000
TDS packets received from server 34 34.0000
Bytes sent from client 3166 3166.0000
Bytes received from server 128802 128802.0000
Time Statistics
Client processing time 156478 156478.0000
Total execution time 572009 572009.0000
Wait time on server replies 415531 415531.0000
答案 0 :(得分:5)
看看Do you use Column=@Param OR @Param IS NULL in your WHERE clause? Don't, it doesn't perform,了解如何使用sp_executesql重写它,这将更好。
这看起来像是一个函数调用吗?
left outer join [dbo].[yaf_Topic] t ON t.TopicID = [dbo].[yaf_forum_lasttopic](b.ForumID,@UserID,b.LastTopicID,b.LastPosted)
也许你的功能搞砸了这个东西,硬编码的东西而不是函数调用,看看它是否会产生巨大的差异
答案 1 :(得分:2)
使用这些IO统计信息,查询必须是阻止的。在SP运行时,检查sys.dm_exec_requests,查看过程运行窗口的session_id(@@ SPID),并查看blocking_session_id,wait_type,wait_time和wait_resource。这些应该指导您阻止的原因。
答案 2 :(得分:1)
我认为你的执行计划没有任何不好。
最有可能的是,另一个会话会锁定您的查询,或者您的服务器负载过重。
答案 3 :(得分:1)
相关子查询逐行运行。将它们转换为连接。
与您的UDF相同。将它们转换为连接应该可以加快速度,因为它们也是逐行运行的。
SQL Menace说的是什么。
答案 4 :(得分:0)
我注意到这张桌子是你最大的罪魁祸首:
表'yaf_UserGroup'。扫描计数231,逻辑读取693,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
我还注意到,查询中的任何地方都没有直接提到违规表。这意味着必须在查询中使用的其中一个UDF中引用它。我的猜测是UDF阻止查询有效地使用yaf_UserGroup
表上的索引。您可以通过将违规UDF中的逻辑直接合并到查询中来纠正此问题。
最后,无论如何解决这个问题,看起来yaf是开源的。这意味着您应该将修复程序返回到原始项目。通过帮助保持代码与基础项目更加一致,这将使您受益,因此未来的更新不会撤消您的性能修复。