【问题标题】:Horrible sql server performance when capturing result in variable捕获变量结果时的可怕 sql server 性能
【发布时间】:2014-07-27 13:37:23
【问题描述】:

我使用的是 SQL Server 2012。

当我运行这个查询时...

select 
    count(*)
from 
    MembershipStatusHistory msh
join 
    gym.Account a on msh.AccountID = a.AccountID
join 
    gym.MembershipType mt on a.MembershipTypeID = mt.MembershipTypeID
join 
    MemberTypeGroups mtg on mt.MemberTypeGroupID = mtg.MemberTypeGroupID
where 
    mtg.MemberTypeGroupID IN (1,2)
    and msh.NewMembershipStatus = 'Cancelled'
    and year(msh.ChangeDate) = year(getdate())
    and month(msh.ChangeDate) = month(getdate())
    and day(msh.ChangeDate) = day(getdate())

...它几乎立即返回。伟大的。现在,当我像这样运行完全相同的查询时:

declare @CancellationsToday int

SET @CancellationsToday = (
    select  
        count(*)
    from MembershipStatusHistory msh
    join gym.Account a
    on msh.AccountID = a.AccountID
    join gym.MembershipType mt
    on a.MembershipTypeID = mt.MembershipTypeID
    join MemberTypeGroups mtg
    on mt.MemberTypeGroupID = mtg.MemberTypeGroupID
    where mtg.MemberTypeGroupID IN (1,2)
    and msh.NewMembershipStatus = 'Cancelled'
    and year(msh.ChangeDate) = year(getdate())
    and month(msh.ChangeDate) = month(getdate())
    and day(msh.ChangeDate) = day(getdate())
)

...返回需要 1.5 分钟。始终如一。

这到底是怎么回事?我必须使用一个变量,因为我需要稍后在我的存储过程中对结果求和。我将其他查询的结果存储在同一个过程中,它们很快。我被难住了。

以下是 SLOW 查询的执行计划:

下面是 FAST 查询的执行计划:

说实话,我不知道这些执行计划是什么意思,或者我需要更正什么。

【问题讨论】:

    标签: sql sql-server sql-server-2012


    【解决方案1】:

    很奇怪,但试试这样的......

    declare @CancellationsToday int;
    
    select @CancellationsToday = count(*)
    from MembershipStatusHistory msh
    join gym.Account a
    on msh.AccountID = a.AccountID
    join gym.MembershipType mt
    on a.MembershipTypeID = mt.MembershipTypeID
    join MemberTypeGroups mtg
    on mt.MemberTypeGroupID = mtg.MemberTypeGroupID
    where mtg.MemberTypeGroupID IN (1,2)
    and msh.NewMembershipStatus = 'Cancelled'
    and year(msh.ChangeDate) = year(getdate())
    and month(msh.ChangeDate) = month(getdate())
    and day(msh.ChangeDate) = day(getdate())
    

    【讨论】:

    • @@ROWCOUNT 始终返回“1”而不是 COUNT 数字。起初我很乐观,因为它确实跑得很快。有任何想法吗?我必须做 SELECT * 而不是 SELECT count(*) 吗?
    • 等一下,使用 SELECT * 不起作用,因为我的一些计数会返回数十万条记录,而这些都会返回到我的应用程序中,当我需要的只是计数。一定有更好的办法。
    • M.Ali,你成功了。这似乎是 mssql 中的一个错误,为什么它会如此不同地对待这两个。无论如何,谢谢!
    【解决方案2】:

    嗯,奇怪,试试这个:

    SELECT @CancellationsToday = COUNT(*) FROM ......
    

    另外值得一提的是不要在WHERE 子句中使用函数。

    我认为你只有msh.ChangeDate 中的日期,用今天的日期创建一个变量,如下所示:

    DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())) 
    

    并在WHERE 子句中使用它。

    【讨论】:

    • msh.ChangeDate 是数据库数据 - 它永远不等于 getdate()。我试过 SELECT @,但没有更快。
    • 我认为他的意思是声明一个名为today的变量,并将其设置为等于DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())),然后在WHERE中比较类似的表达式子句: WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, msh.ChangeDate)) = today ...仅此一项就应该比年/月/日的六个函数调用和比较更有效
    • 好的,抱歉我误会了。
    【解决方案3】:

    您需要查看 SQL Server Management Studio 中这两个查询的执行计划,以了解发生了什么以及原因。您可以添加一个索引来解决问题,或者计划本身可能会告诉您正在发生的事情以及如何解决它。没有这些信息,很难知道该说什么。

    正如我在上面评论的那样,调整 where 子句以摆脱六个函数调用,只需将数据库列的“日期”部分与常量变量进行比较应该会有所帮助。

    另一个小建议是明确说明 INNER JOIN 如果这是您想要的...始终准确指定您想要的连接类型(INNER JOIN、LEFT OUTER JOIN、CROSS JOIN 等),而不仅仅是“加入” '。它使事情更清楚。

    【讨论】:

    • 谢谢,我会检查一下,星期一早上回来报告。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 2012-05-25
    • 2020-03-29
    • 2012-09-12
    • 2012-08-05
    相关资源
    最近更新 更多