【问题标题】:need some help optimizing a stored proc需要一些帮助来优化存储过程
【发布时间】:2012-03-02 23:50:31
【问题描述】:

我有一个存储过程,它正在构建一个动态 sql 查询,然后通过 exec(@sql) 运行它。

存储过程正在连接大约 12 个表。事实上,它的运行速度相对较快。但后来我需要添加一个额外的字段。为此,我创建了一个标量函数,如下所示:

SELECT @weight = @weight +COUNT(*) FROM dbo.UserPDMedication WHERE UserID = @userid
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND HoehnYarhID IS NOT null
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND DateOfBirth IS NOT NULL
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND GenderID IS NOT NULL
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND DateDiagnosed IS NOT null

它基本上只是一个函数,它会根据用户填写的问题数量返回一个 int。因此,对于存储过程中的每个用户,都会调用此函数。存储过程如下所示:

    SELECT DISTINCT u.UserID, u.Healthy, u.DateOfBirth, u.City, st.StateCode AS State, u.GenderID, g.Gender, u.Latitude, u.Longitude, u.PDConditionID, u.Zip, u.Distance,
    (SELECT TOP 1 EmailID FROM Messages m WHERE TrialID = ' + @trialID + ' AND ToUserID = u.userid AND LocationID = ' + @locationID + ') AS MessageID, dbo.UserWeightedValue(u.UserID) as wt
FROM [User] u
    INNER JOIN aspnet_UsersInRoles uir ON u.AspnetUserID = uir.UserId
    INNER JOIN aspnet_Roles r ON uir.RoleId = r.RoleId
    FULL JOIN UserHealthCondition uhc ON u.UserID = uhc.UserID
    FULL JOIN UserMotorSymptom ums ON u.UserID = ums.UserID
    FULL JOIN UserNonMotorSymptom unms ON u.UserID = unms.UserID
    FULL JOIN UserPDMedication updm ON u.UserID = updm.UserID
    FULL JOIN UserPDTreatment updt ON u.UserID = updt.UserID
    FULL JOIN UserSupplement us ON u.UserID = us.UserID
    FULL JOIN UserPDGeneticMarker updgm ON u.UserID = updgm.UserID
    FULL JOIN UserFamilyMember ufm ON u.UserID = ufm.UserID
    FULL JOIN State st ON u.StateID = st.ID
    FULL JOIN Gender g ON u.GenderID = g.ID
WHERE u.UserID IS NOT NULL

(我删除了一些块以尝试保持简短)。此 get 在存储过程中作为动态字符串执行。关于如何优化它以加快速度的任何提示?

谢谢

编辑:我使用这里的建议组合来完成这项工作。尽管我将多个 select 语句组合成 2 个语句,但我保持我的函数不变。然后我将原始存储过程更改为 select 到 ##temp。然后我针对那个临时表运行我的函数。执行时间下降到 3-4 秒。我想我必须对这个问题给予肯定,因为正是他的明确指出让我走上了正确的道路。但是谢谢大家。

【问题讨论】:

  • UserID 是您的User 表的主键吗?
  • 是的,userid 是主键。

标签: sql-server-2008 stored-procedures user-defined-functions scalar


【解决方案1】:

DISTINCT 绝对会像聚合一样导致性能下降。你真的需要吗?通常,当您看到 DISTINCT 时,它表示数据或结构问题正在被消除重复的能力所掩盖,而结构应该自行消除。

之后,我希望将其作为 JOIN 移动,而不是 SELECT 列表中的相关查询。这不是绝对的成功,但优化器通常能够更好地将其纳入计划。

根据您所展示内容的复杂性,我还会查看执行计划。首先要检查的是,您是否进行了全面优化或是否超时。如果它超时,那么你正在处理一个最好的猜测,而不是一个完全计算的“足够好”的计划。如果是这样,您需要考虑简化此查询。如果您有足够好的计划,请查看其中的瓶颈所在。

【讨论】:

  • 需要distinct,否则返回的重复记录太多。在这种情况下,这是因为某些联接表对每个用户都有多条记录。这不是设计缺陷——每个用户都可以为这些特定的表选择多个值。但是,我的函数不会有重复项,因为它使用的是用户表的主键 userid。因此,如果将我的功能移出不同的功能会有所帮助,我可以这样做。如果我运行 select myFunction(userid), user.* from [user] 它会在大约 5 秒内完成查询。
  • 好的。只是检查。这是让人们陷入麻烦的事情之一,尤其是从性能的角度来看。
【解决方案2】:

如果UserID是表User的主键,那么用户填的问题就不用SELECT了,你可以把它包在一个SELECT里:

SELECT @weight = @weight + COUNT(HoehnYarhID) + COUNT(DateOfBirth) + COUNT(GenderID) + COUNT(DateDiagnosed)
FROM dbo.[User] 
WHERE UserID = @userid 

【讨论】:

  • 谢谢。你说得对,我自己也应该注意到这一点。它现在可能会快几秒钟,不确定。我仍然需要在这方面做更多工作以加快速度。
【解决方案3】:

将标量值函数转换为内联表值函数。

【讨论】:

  • 谢谢,我试试这个。不过问题 - 我之前没有创建过表值函数。如何在返回选择中使用参数?如果您查看我的标量函数的原始 sql 代码,您会看到我将总值分配给 @weight。我将查询简化为只有 2 个选择语句。我似乎无法选择 count(2ndtable.*) 所以我无法将它们全部组合成一个选择,因此我需要一个参数。有没有更好的方法来做到这一点?谢谢
猜你喜欢
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
  • 2019-06-02
  • 2011-08-05
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多