【问题标题】:SQL Performance Slow (Improve Insert Into Temp Table)SQL 性能慢(改进插入临时表)
【发布时间】:2016-06-28 15:26:20
【问题描述】:

我一直在研究一个运行缓慢的旧审计存储过程,我在应用索引和使查询更可查询方面取得了一些成功。

但是,存储过程仍然需要一分钟多的时间才能完成。我认为问题在于临时表插入。我确实尝试将索引应用于临时表,但这只会降低性能:

表上的索引数量是最重要的因素 插入性能。表的索引越多,速度越慢 执行成为。插入语句是唯一的操作 不能直接从索引中受益,因为它没有 where 子句。

SQL 代码

我已在审核过程中的代码 sn-p 下方发布了该过程的处理时间最长,并包含了执行计划。

SELECT dbo.[Audit Result Entry Detail].PK_ID,
  dbo.[Audit Result Entry Detail]....... 
   45-50 other columns selected from Audit Result Entry Detail 
   (Note i need to select all these)
   dbo.[Audit Register].Audit_Date,
   dbo.[Audit Register].Audit_Type,
   dbo.[Audit Register].ContextUser
 INTO #temp5

 FROM dbo.[Audit Result Entry Detail]
   INNER 
    JOIN dbo.[Audit Register]
   ON dbo.[Audit Result Entry Detail].FK_RegisterID = dbo.[Audit Register].PK_ID
   INNER 
    JOIN (
     SELECT MAX(Audit_Date) AS DATE,
         FK_RegisterID
       FROM dbo.[Audit Result Entry Detail]
      INNER 
       JOIN dbo.[Audit Register]
      ON dbo.[Audit Result Entry Detail].FK_RegisterID = dbo.[Audit Register].PK_ID
   WHERE Audit_Date >= @StartDate AND Audit_Date < DATEADD(dd,1,@EndDate)
            --WHERE ((SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, Audit_Date))) >= @StartDate 
             -- AND  (SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, Audit_Date))) <= @EndDate)
              AND part_number = @ParticipantNumber
      GROUP 
         BY FK_RegisterID
   ) dt
   ON dbo.[Audit Result Entry Detail].FK_RegisterID = dt.FK_RegisterID
  AND dbo.[Audit Register].Audit_Date = dt.[date]
  WHERE part_number = @ParticipantNumber

执行计划:

我认为瓶颈是#temp5 表,我的问题是有什么方法可以加快插入到临时表中的速度,还是有更好的替代临时表的方法?

【问题讨论】:

  • 请提供执行计划的链接而不是图片
  • 性能问题应该包括EXPLAIN ANALYZE和一些关于表大小、索引、当前时间性能、期望时间等的信息。Slow是一个相对术语,我们需要一个真实的值来比较。
  • 执行计划显示将数据插入临时表需要总时间的 41%。所以我认为它会在临时表中插入大量行,但看起来最终结果只有 3462 行。谁能解释一下?谢谢
  • @Ryan,您在 [Audit Register] 中使用了多少个字段?如果你使用的字段很少,你能有一个覆盖索引吗?
  • @TheGameiswar,我们如何提供执行计划的链接? (仅供参考)

标签: sql sql-server performance stored-procedures temp-tables


【解决方案1】:

我想这个问题可能有几个不同的原因。 至少,假设是因为一条记录中的大量字段会导致临时堆表中的页面溢出。与此同时,tempdb 中可能存在争用,甚至速度很慢。因此,一般建议可能是:
1. 如前所述,尽量不要使用临时表。
2. 如果可能,尽量限制记录大小以适合一页。或者甚至更好,如果您可以在一页中容纳 2-3 条记录。
3. 如果可能,请使用带有聚集索引的“暂存”表,而不是临时表。不要截断那个表,只做删除。
4.如果使用临时表:在插入之前创建带有聚集索引的表。
5. Fallow Paul Randal 对 TempDB 的建议:http://www.sqlskills.com/blogs/paul/the-accidental-dba-day-27-of-30-troubleshooting-tempdb-contention/

对于更深入的故障排除,我建议在执行该查询期间捕获等待、锁定、I/O、内存和 CPU 活动。

【讨论】:

  • 非常感谢您使用回答中的第 4 点提供的帮助,现在存储过程大约在 15 秒内运行。通过更多的调整,我相信我可以让它运行得更快。
  • 在第 1 点中,您建议不要使用临时表,但是您建议使用什么来代替临时表?我查看了表变量、CTE 和派生表。然而,临时表被证明是一个更好的解决方案。
  • 见#3。 “暂存”表。这不是灵丹妙药,但在某些特定情况下可能会有所帮助。我真的不能说这是否是你的情况。你更清楚你的争点在哪里,你可以试试。
  • 我认为应该指出第 4 点并且仅就插入速度而言,在表上拥有聚集索引(实际上是任何索引)实际上会使插入速度变慢,因为它必须同时订购(和/或构建非集群的)。
  • 如果您尝试进行最低限度记录的插入,那是正确的。否则,如果在自然 PK 或接近它的东西上有聚集索引,插入可能会更快,以防您不截断表,但删除(请参阅我的答案中的 #3)。这是因为在删除期间 SQL 会从所有页面中删除单个记录,但不会像 truncate 那样取消分配这些页面。删除要慢得多,但插入要快。
猜你喜欢
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-09
  • 2013-09-05
  • 2011-02-05
  • 2011-08-21
相关资源
最近更新 更多