SQL 查询优化需要 20 - 30 秒才能运行

Posted

技术标签:

【中文标题】SQL 查询优化需要 20 - 30 秒才能运行【英文标题】:SQL Query Optimization taking 20 - 30 secs to run 【发布时间】:2015-10-16 10:33:32 【问题描述】:

下面的查询需要 20 秒来执行,我需要尽可能地优化它。请帮我解决这个问题。

SELECT Distinct 
    qh.QuoteHeaderId, [dbo].[mpx2_Get_PhoneGrade](qh.QuoteHeaderId)
FROM 
    t_QuoteHeader QH
INNER JOIN 
    t_HandsetQuote h ON Qh.QuoteHeaderId = h.QuoteHeaderId
INNER JOIN 
    t_phoneAudit P ON ISNULL(h.InspectionPhoneAuditId, h.QuotePhoneAuditId) = p.PhoneAuditId        
INNER JOIN 
    mpx2_vw_customers C ON qh.CustomerId = C.CustomerId
INNER JOIN 
    @ContactChannels CC ON C.ContactChannelId = CC.ContactChannelId
LEFT OUTER JOIN 
    t_HandsetQuoteAdditionalInfo_TRNX hqa ON hqa.hqid = h.HandsetQuoteId
WHERE 
    ((@VirtualStatusId = 0 OR @VirtualStatusId = -2 OR 
      C.ContactChannelId NOT IN (1, 2, 13, 80)))        
    AND ((@VirtualStatusId = -2) OR
         ('Q'+ CAST(Qh.QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(h.StockStatusId AS VARCHAR(3)) IN
            (SELECT 'Q'+ CAST(QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(StockStatusId AS VARCHAR(3)) FROM t_VirtualStatusMap WHERE (@VirtualStatusId IS NULL OR @VirtualStatusId IN (0,-1)  OR VirtualStatusId = @VirtualStatusId))
        )
    )
    AND ((qh.IsCancelled = 0 and @onlyOpenOrders = 1) OR @onlyOpenOrders = 0)
    AND ((h.IsCancelled = 0 and @onlyOpenOrders = 1) OR @onlyOpenOrders = 0)        
    AND (qh.ConfirmedDate <= @CutOff)

请帮我优化一下。此查询用于存储过程。

【问题讨论】:

在不了解您的数据库结构甚至查看查询计划的情况下,我们怎么可能提供帮助? 对不起,我必须上传执行计划 只是edit这个问题。 现在对你有帮助吗 您只包括了查询计划的一小部分。表和索引结构、行数和统计信息输出将有助于理解这一点 【参考方案1】:

评论太长了。

WHEREON 子句中的ORs 很难优化。通常对于这样的查询,最好基于组件构建查询并使用动态 SQL。

例如,@OnlyOpenOrders 上的条件将包含如下:

declare @sql varchar(max);
set @sql = ' . . .';
declare @where varchar(max);

set @where = 'where . . .';

if (@OnlyOpenOrders = 0) begin
    set @where = @where + ' and qh.IsCancelled = 0 and h.IsCancelled = 0'
end;

set @sql = @sql + ' ' + @where;

exec sp_executesql @sql;

您需要为您使用的所有变量提供类似的逻辑。

【讨论】:

或者使用UNION子句编写查询 @SteveFord 。 . .这是可能的,但是当您有多个条件时,UNION ALL 会变得复杂。【参考方案2】:

有几件事,尽管正如其他人所说,没有所有必需的信息,例如完整的执行计划和所涉及的表的架构,它主要是指导/猜测;

1.) 在这部分中,您会从 QuoteStatusId 和 StockStatusId 构建一个字符串,以便比较它们; ('Q'+ CAST(Qh.QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(h.StockStatusId AS VARCHAR(3)) IN (SELECT 'Q'+ CAST(QuoteStatusId AS VARCHAR(3)) + 'S' + CAST(StockStatusId AS VARCHAR(3)) FROM t_VirtualStatusMap WHERE (@VirtualStatusId IS NULL OR @VirtualStatusId IN (0,-1) OR VirtualStatusId = @VirtualStatusId))) 如果您跳过构建字符串,因为它们由相同的两列组成,并且直接比较两列可能会加快速度。

2.) 您是否尝试添加它在您附加的图片中建议的索引?在没有看到您的架构和执行计划的情况下,很难提出合适的建议,但可能值得添加建议的内容(右键单击绿色文字,它将生成代码以添加建议的索引)。我会阅读索引并确保有适当的索引供查询使用。 ConfirmedDate 似乎是显而易见的,以及所有的连接键。

3.) 正如 Gordon 建议的那样使用动态 sql,或者如果您对此不满意 - 也许将查询分成几个查询并使用 IF 语句在每个查询之间切换,这可以帮助 SQL 为每个场景生成一个好的计划,而不是试图找到一个适用于所有情况的通用计划。

【讨论】:

以上是关于SQL 查询优化需要 20 - 30 秒才能运行的主要内容,如果未能解决你的问题,请参考以下文章

理解/优化 Postgresql 中的 SQL 查询

记一次mysql多表查询(left jion)优化案例

如何优化这个永远需要的 sql 查询?

50 万条记录的 SQL 查询性能优化

大数据量实时统计排序分页查询 优化总结

如何优化查询 - Ef core