查询的SQL Server执行时间呈指数级增长

时间:2012-12-19 15:36:59

标签: sql-server performance execution-time

我在运行连接多个表的查询时遇到了一些性能问题。主表有1.7亿条记录,所以它非常大。

我遇到的是当我使用前1000条款运行查询时,结果是即时的。但是,当我将其增加到前8000时,查询很容易运行15分钟(然后我将其杀死)。通过反复试验,我发现引人注目的是Top 7934(就像魅力一样)和Top 7935(永远运行)

是否有人认识到这种行为并看到我做错了什么?也许我的查询在某些方面有问题。

提前致谢

SELECT  top 7934 h.DocIDBeg
    ,h.[Updated By]
    ,h.Action
    ,h.Type
    ,h.Details
    ,h.[Update Date]
    ,h.[Updated Field Name]
    ,i.Name AS 'Value Set To'
    ,COALESCE(i.Name,'') + COALESCE(h.NewValue, '') As 'Value Set To'
    ,h.OldValue
FROM
    (SELECT  g.DocIDBeg
            ,g.[Updated By]
            ,g.Action
            ,g.Type
            ,g.Details
            ,g.[Update Date]
            ,CAST(g.details as XML).value('auditElement[1]/field[1]/@name','nvarchar(max)') as 'Updated Field Name'
            ,CAST(g.details as XML).value('(/auditElement//field/setChoice/node())[1]','nvarchar(max)') as 'value'
            ,CAST(g.details as XML).value('(/auditElement//field/newValue/node())[1]','nvarchar(max)') as 'NewValue'
            ,CAST(g.details as XML).value('(/auditElement//field/oldValue/node())[1]','nvarchar(max)') as 'OldValue'
    FROM(
            SELECT a.ArtifactID
                  ,f.DocIDBeg
                  ,b.FullName AS 'Updated By'
                  ,c.Action
                  ,e.ArtifactType AS 'Type'
                  ,a.Details
                  ,a.TimeStamp AS 'Update Date'
            FROM [EDDS1015272].[EDDSDBO].[AuditRecord] a
                        LEFT JOIN [EDDS1015272].[EDDSDBO].AuditUser b
                            ON a.UserID = b.UserID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].AuditAction c
                            ON a.Action = c.AuditActionID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].[Artifact] d
                            ON a.ArtifactID = d.ArtifactID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].[ArtifactType] e
                            ON d.ArtifactTypeID = e.ArtifactTypeID
                        INNER JOIN [EDDS1015272].[EDDSDBO].[Document] f
                            ON a.ArtifactID = f.ArtifactID
            ) g
    ) h
LEFT JOIN [EDDS1015272].[EDDSDBO].[Code] i
ON h.value = i.ArtifactID

3 个答案:

答案 0 :(得分:2)

“通过反复试验,我发现引人注目的是Top 7934(就像魅力一样)和Top 7935(永远运行)”

这听起来非常像漏油事件。 Adam Mechanic在下面的视频中做了一个很好的内部演示。基本上顶部强制要求记忆的那种。如果内存授予量不足以完成操作,则其中一些内容将在磁盘上完成。

https://www.youtube.com/watch?v=j5YGdIk3DXw

请到1:03:50看看Adam演示漏油事件。在他的查询中,668,935行不溢出,但668,936行,查询时间超过两倍。

如果有时间,请观看整个会话。非常适合性能调整!

也可能是@Remus建议的引爆点,但在不知道实际计划的情况下,这一切都在猜测。

答案 1 :(得分:2)

我曾经经常使用数据仓库,经常遇到类似的问题。根本原因显然是内存使用,就像这里已经提到的那样。我不认为如果你真的需要查询所有1.7亿条记录,重写你的查询会有很大的帮助,我认为你不等待更多的内存资源。 所以这里只是一个简单的解决方法:

尝试拆分您的查询。例如,首先从连接到AuditUser表的AuditRecord记录表中查询所需的所有数据,并将结果存储在另一个(例如临时表)表中。然后将这个新表与Artifact表连接起来,依此类推。在这种情况下,这些步骤将逐个需要更少的内存,然后运行整个查询并将其挂起。因此,从长远来看,你将不会有一个查询,而是一个易于跟踪的脚本,因为你可以在控制台中打印出一些状态,这将完成他的工作,而不是永远不会结束的查询

还要确保您确实需要一次查询所有这些数据,因为我可以想到没有用例为什么需要它,但是如果它是一个应用程序那么你应该实现分页,如果它是一些导出功能那么也许你可以用一个时间轴来批量处理数据。例如,每天导出数据并仅查询yersterday中的数据。在这种情况下,您将提出增量导出。

答案 2 :(得分:0)

我认为子选择强制服务器在应用过滤器之前获取所有内容 这将使更多的内存使用(xlm字段),并使其难以使用体面的qry计划

关于奇怪的顶级行为:top对qry计划生成有很大影响。 7935可能是1个最佳计划的截止点,并且当需要获取更多时,sql server将选择不同的路径。 或者它可以回到内存并耗尽7935上的mem

更新

我重新设计你的qry以消除嵌套选择,我不是说它现在会变得更快,但它消除了一些未使用的字段,它应该更容易理解和优化基于qry计划。 因为我们现在没有每张桌子的确切尺寸,我们几乎无法运行qry来测试它不可能给你最好的答案。但我可以尝试一些提示:

一步是检查是否需要所有左连接并将其转换为内部(如果不需要):AuditUser,AuditRecord可以始终拥有用户吗?

您可以尝试的另一件事是将优先级较小的表的数据放在tmp表中,并将较大的表连接到该tmp表,可能会删除大量要加入的记录

如果可能的话,你可以对一点进行非规范化处理,例如将用户名放在auditrecord 2中,这样就可以完全消除AuditUser上的连接

但是你需要能够/你被允许使用的数据/服务器

SELECT  top 7934 f.DocIDBeg
    ,b.FullName AS 'Updated By'
    ,c.Action
    ,e.ArtifactType AS 'Type'
    ,a.Details
    ,a.TimeStamp AS 'Update Date'
    ,CAST(a.Details as XML).value('auditElement[1]/field[1]/@name','nvarchar(max)') as 'Updated Field Name'
    ,i.Name AS 'Value Set To'
    ,COALESCE(i.Name,'') + COALESCE(CAST(a.Details as XML).value('(/auditElement//field/newValue/node())[1]','nvarchar(max)') as 'NewValue', '') As 'Value Set To'
    ,CAST(a.Details as XML).value('(/auditElement//field/oldValue/node())[1]','nvarchar(max)') as 'OldValue'
FROM [EDDS1015272].[EDDSDBO].[AuditRecord] a
                        LEFT JOIN [EDDS1015272].[EDDSDBO].AuditUser b
                            ON a.UserID = b.UserID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].AuditAction c
                            ON a.Action = c.AuditActionID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].[Artifact] d
                            ON a.ArtifactID = d.ArtifactID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].[ArtifactType] e
                            ON d.ArtifactTypeID = e.ArtifactTypeID
                        INNER JOIN [EDDS1015272].[EDDSDBO].[Document] f
                            ON a.ArtifactID = f.ArtifactID
                        LEFT JOIN [EDDS1015272].[EDDSDBO].[Code] i
                            ON CAST(a.details as XML).value('(/auditElement//field/setChoice/node())[1]','nvarchar(max)') = i.ArtifactID