SQL Server:查询性能分析 - 任何优化想法?

Posted

技术标签:

【中文标题】SQL Server:查询性能分析 - 任何优化想法?【英文标题】:SQL Server : Query performance analysis - Any Optimization ideas? 【发布时间】:2013-10-02 16:18:16 【问题描述】:

我已经阅读了多篇推荐使用 SQL Server Profiler 的文章,我也是。

我有一个非常重要的查询,它使应用程序不时冻结。查询包含多个LEFT JOIN ... ON ... AND (... AND ...) OR (... AND ...)

我对正在使用的关系模型没有权限,所以我必须使用它。

查询是关于在发生火灾时获取附近的危险品场所,以帮助规划消防人员的干预计划。查询有效,只需要一些优化。

现在,我有这个查询有6635 Reads296 CPU0 Writes281 Duration

我能想到的只是查询太慢而且服务器执行起来可能太重了。换句话说,它根本不是最优的。

如果它很重要,因为我相信它确实如此,查询在其 where 子句中有多个计算,例如:

ATN2(SQRT(SIN(RADIANS(@latitude - CASE WHEN LocationType = @locationType THEN Buildings.Latitude ELSE Intersections.Latitude END) / 2 *...

我没有购买工具或其他任何东西的预算。

更新

根据要求,这是一个可怕的查询:

SELECT PHM.ID, HP.Name, PHMD.TL, PHMD.QTY
    , PHMD.CT, PHMD.C, PHMD.MU
    , HP.HR, HP.FR, HP.RR, HP.SR
    , PHMD.CP
    , A.HN, A.Alpha
    , CASE WHEN PHM.LT <> @7 THEN TL.D ELSE TL.D + ' ' + TL2.D END AS TLcol
    , C.D AS CD
FROM PHM 
    LEFT JOIN PHMD ON PHMD.ExID = PHM.ID 
    LEFT JOIN HP ON PHMD.HPID = HP.ID 
    LEFT JOIN BP ON PHM.LT=@5 
        AND BP.ID = PHM.BPID 
    LEFT JOIN A ON (PHM.LT=@4 
            AND A.ID = PHM.AID) 
        OR (PHM.LT=@5 
            AND BP.AID = A.ID) 
    LEFT JOIN I ON I.ID = PHM.IID  
    LEFT JOIN TL ON (PHM.LT<>@7 
            AND A.TLID = TL.ID) 
        OR (PHM.LT=@7 
            AND I.TLID1 = TL.ID)  
    LEFT JOIN TL AS TL2 ON PHM.LT=@7 
        AND I.TLID2 = TL2.ID 
    LEFT JOIN C ON TL.CID=C.ID 
    LEFT JOIN B ON A.ID = B.ExID 
    LEFT JOIN B ON B.ID = B.BID 
WHERE EXISTS (SELECT * FROM PHMD WHERE PHMD.ExID=PHM.ID)
    AND (((PHM.LT=@4 AND PHM.AID=@8)    
        OR (PHM.LT=@5 AND PHM.BPID IN (SELECT ID FROM BP WHERE AID=@8)) 
    OR (PHM.LT=@6 AND PHM.BID IN (SELECT BID FROM B WHERE ExID=@8))) 
     AND PHM.DV = (
            SELECT MAX(PHMLD.DV) 
                FROM PHM AS PHMLD 
                WHERE PHMLD.LT = PHM.LT 
                    AND ISNULL(PHMLD.AddressID,0) = ISNULL(PHM.AID,0) 
                    AND ISNULL(PHMLD.SuiteID,0) = ISNULL(PHM.SID,0) 
                    AND ISNULL(PHMLD.BPID,0) = ISNULL(PHM.BPID,0) 
                    AND ISNULL(PHMLD.IID,0)=ISNULL(PHM.IID,0) 
                    AND ISNULL(PHMLD.BID,0)=ISNULL(PHM.BID,0)) 
                    OR 6371010 * (2 * ATN2(
                            SQRT((SIN(RADIANS(@1 - CASE WHEN PHM.LT<>@6 THEN B.LAT ELSE I.LAT END)/2) 
                                * SIN(RADIANS(@1 - CASE WHEN PHM.LT<>@6 THEN B.LAT ELSE I.LAT END)/2) 
                                + COS(RADIANS(CASE WHEN PHM.LT<>@6 THEN B.LAT ELSE I.LAT END)) 
                                * COS(RADIANS(@1)) 
                                * SIN(RADIANS(@2 - CASE WHEN PHM.LT<>@6 THEN B.LNG ELSE I.LNG END)/2) 
                                * SIN(RADIANS(@2 - CASE WHEN PHM.LT<>@6 THEN B.LNG ELSE I.LNG END)/2)))
                            , SQRT(1-(SIN(RADIANS(@1 - CASE WHEN PHM.LT<>@6 THEN B.LAT ELSE I.LAT END)/2) 
                                * SIN(RADIANS(@1 - CASE WHEN PHM.LT<>@6 THEN B.LAT ELSE I.LAT END)/2) 
                                + COS(RADIANS(CASE WHEN PHM.LT<>@6 THEN B.LAT ELSE I.LAT END)) 
                                * COS(RADIANS(@1)) 
                                * SIN(RADIANS(@2 - CASE WHEN PHM.LT<>@6 THEN B.LNG ELSE I.LNG END)/2) 
                                * SIN(RADIANS(@2 - CASE WHEN PHM.LT<>@6 THEN B.LNG ELSE I.LNG END)/2))))
                        ) <= @3)

SET SHOWPLAN_XML ON更新

请访问以下链接了解执行展示计划。 http://pastebin.com/k6GxxSKF

感谢您的热心帮助! =)

【问题讨论】:

不确定您是否会在这方面获得很多帮助,因为您并没有真正提出问题……如果您怀疑它不是最佳的并且需要优化,您需要发布查询...不确定我是否可以为这些小信息提供很多帮助。 Or 语句的左连接永远不会有趣......有时最好在一组条件上执行两个左连接,然后是下一个,而不是将所有逻辑都放在 Or 语句中。 @Twelfth:我会在几秒钟内更新完整的查询。 @Twelfth:刚刚将查询添加到问题中。谢谢你的好眼光! =) 不用担心,如果我们不添加这个问题会被跳过。 from 语句看起来很干净,这对夫妇或语句应该无关紧要。但是我怀疑包含几个子选择的 where 子句会导致运行时间更长。除非下面提供了更好的答案......我会对此进行一些试验和错误。在 where 子句中运行单个 PHM.ID 的查询,然后从 where 子句中删除整个 'exists' 语句并再次运行。比较两次运行的分析器结果,看看您在删除该存在子句时看到了多少变化。 @Twelfth:当我执行 COUNT(PHM.ID) 时,执行时间甚至更长(持续时间超过 550 毫秒)。我通过在 PHMD 上执行 INNER JOIN 而不是 LEFT JOIN 来摆脱 WHERE 中的 EXISTS() 子句,并要求它稍后存在。 【参考方案1】:

查看查询执行计划,我可以看到大部分时间花在 LEFT OUTER 连接上。查询计划显示 73% 的查询时间/资源花在那个连接上。

你需要左外连接吗?

大多数查询都使用索引查找并返回非常少的行,这与它所获得的一样好。然而,他们使用NESTED LOOP 连接,这不是最有效的连接类型。我怀疑如果您强制使用MERGE 甚至HASH 连接类型,您可能会看到不同的性能。请参阅this link,了解如何强制使用另一种类型的JOIN。但这并不是真正推荐的。

这些表格是否经常更新?还是它们非常静态?还有这些表中有多少数据。我怀疑如果 SQL Server 使用了错误的 JOIN 类型,则可能是表上的统计信息已过时。尝试在表上运行UPDATE STATISTICS 并检查查询计划是否更改。

【讨论】:

+1 用于指出如何获取 XML 执行计划,并接受了用于指出如何分析执行计划以提高性能的答案。 @WillMarcouiller:您可以将 XML 输出保存到 .sqlplan 文件中,然后当您在 SSMS 中打开该 sqlplan 文件时,它将为您提供查询执行计划的可视化表示,这更容易比 XML 读。一个技巧将 xml 保存到一个文件中,比如 file1.sqlplan 在 SSMS 中关闭文件然后重新打开它。可移植的执行计划。

以上是关于SQL Server:查询性能分析 - 任何优化想法?的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 性能优化实战系列

大型sql server查询性能优化

Sql Server 优化 SQL 查询:如何写出高性能SQL语句

SQL Server 2008 R2:优化查询性能

SQL Server SQL性能优化之--pivot行列转换减少扫描计数优化查询语句

SQL Server 查询性能优化——创建索引原则