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 Reads
、296 CPU
、0 Writes
、281 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 查询:如何写出高性能SQL语句