运行 DELETE 存储过程,但发现 WHILE 循环中的性能随着迭代次数的增加而下降

use*_*615 3 performance sql-server t-sql sql-server-2008-r2 performance-tuning

有一个快速的一般问题。我有一张桌子,我正在尝试清除一张桌子。我正在使用批次之间的时间为 50 毫秒和每批次 2000 条记录的WHILE循环进行删除WAITFOR DELAY。真正的问题是,随着时间的推移,删除的记录数量会随着时间的推移而下降。请参阅以下内容:

Minute Number | Number of Records Deleted:

            1 | 162,000 
            2 | 116,000 
            3 |  80,000 
            4 |  72,000 
            5 |  62,000 
            6 |  38,000 
            7 |  38,000 
            8 |  34,000 
            9 |  20,000
Run Code Online (Sandbox Code Playgroud)

想知道使用WHILE循环批处理删除记录是否有一些基本的东西会导致性能随着循环的每次迭代而降低。我们一直在手动观察性能,然后在性能在第 5 到第 6 分钟左右开始急剧下降时停止 proc,然后再次重新启动部署。我们不认为这是一个直接的锁定问题,因为当我们使用批量大小时,性能总是在 5 到 6 分钟左右下降。

Mar*_*ith 5

您说性能会随着执行次数的增加而降低,并且“重新启动部署”可以修复它。

我不清楚你说的那个特定短语是什么意思,但假设它涉及停止循环,然后在一段时间后重新启动它,那么一种可能性是ghost records

我创建了一个如下表(每页一行,以便于数学)

CREATE TABLE T
  (
     X INT PRIMARY KEY,
     Y CHAR(8000)
  )

INSERT INTO T
SELECT TOP 100000 ROW_NUMBER() OVER (ORDER BY (SELECT 0)),
                  'Y'
FROM   master..spt_values v1,
       master..spt_values v2
Run Code Online (Sandbox Code Playgroud)

并假设您的DELETE过程正在清除由某些升序列标识的旧行。

SET STATISTICS IO ON;

DECLARE @i INT = 0;
WHILE @i < 10
  BEGIN
      SET @i+=1

      RAISERROR('Processing %d',0,1, @i) WITH NOWAIT

      DELETE TOP (2000) FROM T
      WHERE  X <= 50000

      /*50 MS Delay*/
      WAITFOR DELAY '00:00:00:050'

      SELECT ghost_record_count,
             version_ghost_record_count
      FROM   sys.dm_db_index_physical_stats(db_id(), OBJECT_ID('T'), NULL, NULL, 'DETAILED')
      WHERE  index_level = 0
  END 
Run Code Online (Sandbox Code Playgroud)

结果

+---------------+--------------------+----------------------------+
| logical reads | ghost_record_count | version_ghost_record_count |
+---------------+--------------------+----------------------------+
|          2018 |               2000 |                          0 |
|          4025 |               4000 |                          0 |
|          6033 |               6000 |                          0 |
|          8026 |               7965 |                          0 |
|         10004 |               9944 |                          0 |
|         11989 |              11920 |                          0 |
|         13977 |              13902 |                          0 |
|         15963 |              15882 |                          0 |
|         17954 |              17864 |                          0 |
|         19943 |              19849 |                          0 |
+---------------+--------------------+----------------------------+
Run Code Online (Sandbox Code Playgroud)

记录不会立即删除。它们开始被标记为幽灵,然后被后台任务清除。在上面的测试中,很少有人在 10 次迭代中被清除,这意味着第十DELETE次的读取次数是第一次的 10 倍。

可能在您的环境中,DELETEs 的发生率高于幽灵清理任务处理它们的速度,从而导致性能持续下降。