SQL 命令运行缓慢。需要帮助识别缓慢

Posted

技术标签:

【中文标题】SQL 命令运行缓慢。需要帮助识别缓慢【英文标题】:SQL command running slow. Need help identifying slowness 【发布时间】:2014-11-06 16:45:59 【问题描述】:

我有一个 SQL 查询需要数小时才能运行。基本上,我希望在我们的“页面”表中找到具有特殊字符的文档 (PDF)。我在 PDFFile 表中找到了这些 PDF。仅执行第一个 AND 子句会在 16 秒内返回。添加第二个子句使 SQL 需要 3 小时。试图弄清楚我做错了什么。非常感谢任何帮助。

查询:

select b.bookletname, b.trackingID, b.[version], s.name
from page p
inner join section s on s.id = p.sectionid
inner join booklet b on b.id = s.bookletid
INNER JOIN [user] u ON b.CreatedBy = u.id
INNER JOIN client c ON c.id = u.clientID
WHERE u.clientID = 2
AND p.[filename] IN (
    SELECT DISTINCT pdf.[FileName]
    FROM PDFFile pdf
    WHERE pdf.fileName LIKE '%\<%' ESCAPE '\'
    OR pdf.fileName LIKE '%\>%' ESCAPE '\'
    OR pdf.fileName LIKE '%\"%' ESCAPE '\'
    OR pdf.fileName LIKE '%\%%' ESCAPE '\'
    OR pdf.fileName LIKE '%''%' ESCAPE '\'
    OR pdf.fileName LIKE '%\*%' ESCAPE '\'
    OR pdf.fileName LIKE '%\+%' ESCAPE '\'
    OR pdf.fileName LIKE '%\\%' ESCAPE '\'
    OR pdf.fileName LIKE '%\/%' ESCAPE '\'
    OR pdf.fileName LIKE '%\:%' ESCAPE '\'
    OR pdf.fileName LIKE '%\?%' ESCAPE '\'
    OR pdf.fileName LIKE '%\[%' ESCAPE '\'
    OR pdf.fileName LIKE '%\]%' ESCAPE '\'
    OR pdf.fileName LIKE '%\|%' ESCAPE '\'
)
OR p.[PDF_File_Name] IN (
    SELECT DISTINCT pdf.[FileName]
    FROM PDFFile pdf
    WHERE pdf.fileName LIKE '%\<%' ESCAPE '\'
    OR pdf.fileName LIKE '%\>%' ESCAPE '\'
    OR pdf.fileName LIKE '%\"%' ESCAPE '\'
    OR pdf.fileName LIKE '%\%%' ESCAPE '\'
    OR pdf.fileName LIKE '%''%' ESCAPE '\'
    OR pdf.fileName LIKE '%\*%' ESCAPE '\'
    OR pdf.fileName LIKE '%\+%' ESCAPE '\'
    OR pdf.fileName LIKE '%\\%' ESCAPE '\'
    OR pdf.fileName LIKE '%\/%' ESCAPE '\'
    OR pdf.fileName LIKE '%\:%' ESCAPE '\'
    OR pdf.fileName LIKE '%\?%' ESCAPE '\'
    OR pdf.fileName LIKE '%\[%' ESCAPE '\'
    OR pdf.fileName LIKE '%\]%' ESCAPE '\'
    OR pdf.fileName LIKE '%\|%' ESCAPE '\'
)
OR p.[PDFName] IN (
    SELECT DISTINCT pdf.[FileName]
    FROM PDFFile pdf
    WHERE pdf.fileName LIKE '%\<%' ESCAPE '\'
    OR pdf.fileName LIKE '%\>%' ESCAPE '\'
    OR pdf.fileName LIKE '%\"%' ESCAPE '\'
    OR pdf.fileName LIKE '%\%%' ESCAPE '\'
    OR pdf.fileName LIKE '%''%' ESCAPE '\'
    OR pdf.fileName LIKE '%\*%' ESCAPE '\'
    OR pdf.fileName LIKE '%\+%' ESCAPE '\'
    OR pdf.fileName LIKE '%\\%' ESCAPE '\'
    OR pdf.fileName LIKE '%\/%' ESCAPE '\'
    OR pdf.fileName LIKE '%\:%' ESCAPE '\'
    OR pdf.fileName LIKE '%\?%' ESCAPE '\'
    OR pdf.fileName LIKE '%\[%' ESCAPE '\'
    OR pdf.fileName LIKE '%\]%' ESCAPE '\'
    OR pdf.fileName LIKE '%\|%' ESCAPE '\'
)

【问题讨论】:

这么多LIKEs,怎么能不慢呢? 为什么您的 PDF 表格有两个单独的文件名列?如果其中一个可以为空,你可以使用COALESCE()吗? @Lamak:尤其是 LIKE 和前导 % --> 确保 没有索引 可以使用! 【参考方案1】:

使用exists 重写并简化likes。 SQL Server 允许您在模式中拥有字符列表,并且您拥有的大多数字符都不需要转义(我希望我得到的模式完全正确)。

我会推荐:

select b.bookletname, b.trackingID, b.[version], s.name
from page p inner join
     section s
     on s.id = p.sectionid inner join
     booklet b
     on b.id = s.bookletid inner join
     [user] u
     on b.CreatedBy = u.id inner join
     client c 
     on c.id = u.clientID
where u.clientID = 2 and
      (exists (select 1
               from PDFFile pdf
               where pdf.fileName LIKE '%[<>"''*+\\/:?\[\]|]%' ESCAPE '\' and
                     pdf.fileName = p.filename
              ) or
       exists (select 1
               from PDFFile pdf
               where pdf.fileName LIKE '%[<>"''*+\\/:?\[\]|]%' ESCAPE '\' and
                     pdf.fileName = p.PDF_File_Name
              ) or
       exists (select 1
               from PDFFile pdf
               where pdf.fileName LIKE '%[<>"''*+\\/:?\[\]|]%' ESCAPE '\' and
                     pdf.fileName = p.PDFName
              )
      );

您希望确保在PDFFile(fileName) 上有一个索引以提高性能。

我也改变了逻辑。你原来的逻辑就像where A and B or C or D 被解析为where (A and B) or C or C。我将其更改为where A and (B or C or D)。这也可能导致性能瓶颈。

【讨论】:

嘿@Gordon Linoff。绝对对您的答案感兴趣,但它有语法错误... Msg 102, Level 15, State 1, Line 14 '\' 附近的语法不正确。 Msg 105, Level 15, State 1, Line 24 字符串 ' 和 pdf.fileName = p 后面的非闭合引号。 PDFName ) ) '. 不确定如何修复,否则我会。 已修复。这真太了不起了。谢谢!【参考方案2】:

尝试删除三个表命中并将该选择放入临时表,因为您使用相同的选择来检查三列。所以你可以在 where 条件下使用临时表。

SELECT DISTINCT pdf.[FileName]
INTO   #temp
FROM   PDFFile pdf
WHERE  pdf.fileName LIKE '%\<%' ESCAPE '\'
        OR pdf.fileName LIKE '%\>%' ESCAPE '\'
        OR pdf.fileName LIKE '%\"%' ESCAPE '\'
        OR pdf.fileName LIKE '%\%%' ESCAPE '\'
        OR pdf.fileName LIKE '%''%' ESCAPE '\'
        OR pdf.fileName LIKE '%\*%' ESCAPE '\'
        OR pdf.fileName LIKE '%\+%' ESCAPE '\'
        OR pdf.fileName LIKE '%\\%' ESCAPE '\'
        OR pdf.fileName LIKE '%\/%' ESCAPE '\'
        OR pdf.fileName LIKE '%\:%' ESCAPE '\'
        OR pdf.fileName LIKE '%\?%' ESCAPE '\'
        OR pdf.fileName LIKE '%\[%' ESCAPE '\'
        OR pdf.fileName LIKE '%\]%' ESCAPE '\'
        OR pdf.fileName LIKE '%\|%' ESCAPE '\' 

SELECT b.bookletname,
       b.trackingID,
       b.[version],
       s.NAME
FROM   page p
       INNER JOIN section s
               ON s.id = p.sectionid
       INNER JOIN booklet b
               ON b.id = s.bookletid
       INNER JOIN [user] u
               ON b.CreatedBy = u.id
       INNER JOIN client c
               ON c.id = u.clientID
WHERE  u.clientID = 2
       AND p.[filename] IN (SELECT *
                            FROM   #temp)
        OR p.[PDF_File_Name] IN (SELECT *
                                 FROM   #temp)
        OR p.[PDFName] IN (SELECT *
                           FROM   #temp) 

【讨论】:

这行得通。确定的性能提升。从3个多小时到10分钟。将尝试 +1 的其他解决方案,看看他的解决方案是否表现更好。感谢您的回答d(-_-)b

以上是关于SQL 命令运行缓慢。需要帮助识别缓慢的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 R2 中运行缓慢的存储过程

在 Azure SQL 上运行非常缓慢的外部表上选择

Groovy 中的 sql.rows() 运行缓慢

为啥 Docker 构建命令在 Elastic Beanstalk 中运行如此缓慢?

存储过程在第一次运行时运行缓慢

postgresql,查询运行缓慢