2

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

我遇到的是,当我使用 top 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
4

3 回答 3

3

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

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

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

于 2012-12-19T18:01:53.213 回答
2

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

这听起来很像泄漏。Adam Mechanic 在下面的视频中做了一个很好的内部演示。基本上顶部强制需要内存的排序。如果内存授予不足以完成操作,则其中一些会在磁盘上完成。

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

前往 1:03:50 观看 Adam 演示泄漏。在他的查询中,668,935 行没有溢出,但 668,936 行溢出,查询时间增加了一倍以上。

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

正如@Remus 所建议的那样,也可能是转折点,但这一切都是在不知道实际计划的情况下猜测。

于 2012-12-19T15:51:19.857 回答
0

我认为子选择会强制服务器在应用过滤器之前获取所有内容,这将导致更多的内存使用(xlm 字段)并且很难使用像样的 qry 计划

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

更新:

我重新设计了您的 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
于 2012-12-19T15:55:14.873 回答