2012-12-19 72 views
2

运行查询连接多个表时,我目前遇到了一些性能问题。主表有1.7亿条记录,所以它非常大。查询的SQL Server执行时间呈指数增长

我遇到的是,当我用top 1000子句运行查询时,结果是即时的。但是,当我将它增加到8000时,查询很容易运行15分钟(然后我杀死它)。通过试验和错误,我发现引爆点是顶7934(作品像一个魅力)和顶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 
+0

显示您的查询计划。 –

+2

该行为甚至被命名为“临界点”:[The Index Tipping Point](http://www.sqlskills.com/blogs/kimberly/category/the-tipping-point.aspx) –

+0

感谢您的快速回复。 @David这里发布执行计划的最佳方法是什么?这是相当复杂的 –

回答

2

“经过反复试验,我发现,引爆点是顶部7934(就像一个魅力)和Top 7935(奔跑永远)”

这听起来非常像泄漏。 Adam Mechanic在下面的视频中做了一个很好的内部演示。基本上,顶部强迫需要记忆。如果内存授权不足以完成操作,则其中的一部分将在磁盘上完成。

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

转至1点03分50秒,看看亚当演示泄漏。在他的查询中,668,935行不会溢出,但是668,936行会使查询时间增加一倍以上。

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

也可能是引爆点,就像@Remus建议的那样,但是这都是猜测而不知道实际的计划。

+0

感谢您的链接。我会看看视频。我目前正试图找出如何实际得到执行计划stakoverflow –

0

我觉得子查询,迫使服务器获取所有之前的过滤器可应用于 这将职高使用更多内存(XLM领域),并使其难以用一个像样的QRY计划

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

更新:

我返工你的QRY消除嵌套的选择,我不是说其现在将是mutch快,但它消除了一些werent使用的字段,它应该能够根据qry计划理解和优化。 因为我们现在不需要每张表的确切大小,我们很难运行qry来测试它不可能给你最好的答案。但我可以尝试一些技巧:

1步是检查是否需要所有的左联接,把它们变成内如果不需要前它: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 
+0

感谢您的答复。非常感激。由于我对SQL很陌生,因此我不了解如何重构查询,因此不需要子查询。任何想法呢? –

+0

基本上,你从最低选择中选择clouse并将其从第一个选择移动到from,然后可以从表格中自行取得所有字段。如果你想要更多的信息,我可以帮助明天(在这里留下时间;)) – ufosnowcat

2

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

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

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