由于 where 子句中的 <>,查询耗时过长

Posted

技术标签:

【中文标题】由于 where 子句中的 <>,查询耗时过长【英文标题】:Query takes too long because of <> in where clause 【发布时间】:2021-11-13 20:42:03 【问题描述】:

我正在构建一个通过电子邮件发送的脚本。我有一张交易表,我只想在状态为 "failed" 时通过电子邮件发送。该表现在有大约 5000 万行,并且会不断增加,我无法存档。

这是查询:

if exists (select top 1 1 from TicketTransactionDetails where ServiceStatus != 0)
begin
DECLARE @tablehtml  NVARCHAR(MAX) ;  
  
    SET @tableHTML =  
        N'<H1>Transactions Status</H1>' +  
        N'<table border="1">' +  
        N'<tr><th>TransactionDate</th><th>NbOfRecords</th>' +  
        N'<th>ServiceStatus</th><th>StatusDescription</th><th>RunDate</th></tr>' +  
        CAST ( (select  td = CAST(InsertDate as date), '',
                        td = COUNT(*),'',
                        td = ServiceStatus,'',
                        td = b.StatusDescription,'',
                        td = GETDATE() 
            from TicketTransactionDetails a 
            inner join ServiceStatuses b on a.ServiceStatus = b.StatusID
            where ServiceStatus = 0
            group by CAST(InsertDate as date),ServiceStatus,b.StatusDescription
            order by CAST(InsertDate as date) desc 
                  FOR XML PATH('tr'), TYPE   
        ) AS NVARCHAR(MAX) ) +  
        N'</table>' ;  

        exec msdb.dbo.sp_send_dbmail
        @profile_name = 'DB_Maintenance',
        @recipients = 'a.a@a.a',
        @subject = 'Tranzanctions with errors',
        @body = @tableHTML,  
    @body_format = 'html';
end

执行(约 25 秒)需要很多时间的是:

select top 1 1 from TicketTransactionDetails where ServiceStatus != 0

有没有办法改进我的查询?

非常感谢。

【问题讨论】:

您需要提供表定义、索引定义和执行计划(使用“粘贴计划”)以获得性能建议。 如果您没有关于 ServiceStatus 的索引肯定从那里开始,您也可以尝试用大于比较替换您的 != 比较,假设这适用于 ServiceStatus 值。使用“不等于”的查询可能会很慢。 正确的索引可能就是您所需要的。事实上,SSMS 甚至可能会向您推荐它。 您的代码对我来说似乎有缺陷。您首先检查ServiceStatus != 0,但您的查询过滤器为ServiceStatus = 0 "Tranzanctions" != 我使用的语言中的 "Transactions"。 【参考方案1】:

你可以做几件事 -

首先,检查ServiceStatus 列是否有索引。如果没有,则创建它。确实应该这样做。

虽然有风险,但另一个选择是在查询中添加 (nolock) 提示。这将绕过表上持有的任何锁

select top 1 1 from TicketTransactionDetails (nolock) where ServiceStatus != 0

【讨论】:

nolock 用于消息队列听起来是个非常糟糕的主意。 感谢您的指点。列上没有索引。我会用索引看看它是如何工作的,我确实不希望使用 nolock 如果你推荐NOLOCK,你应该强调使用这种提示的所有后果,这样OP就不会变得讨厌当他们获得的数据不是他们期望的数据时,他们会感到惊讶。 不要推荐nolock 我已经建立了一个索引,但它并不完美。谢谢大家【参考方案2】:

改用count,count的表现比top好很多

if exists (select count(1) from TicketTransactionDetails where ServiceStatus != 0)

【讨论】:

以上是关于由于 where 子句中的 <>,查询耗时过长的主要内容,如果未能解决你的问题,请参考以下文章

Linq查询where子句返回null

Linq to Entities 中的动态 where 子句 (OR)

SQL语句中,为啥where子句不能使用列别名,而order by却可以?

LINQ where 子句中的 async/await 不起作用

WHERE 子句中的 CASE

无法找出复杂子句中的 PSQL where 问题