从中加速巨大删除的方法,没有条款

dba.stackexchange https://dba.stackexchange.com/questions/1750

  •  16-10-2019
  •  | 
  •  

使用SQL Server 2005。

我正在执行巨大的删除,没有任何条款。它基本上等同于截断表语句 - 除了我不允许使用截断。问题是桌子很大 - 一千万行,需要一个多小时才能完成。有没有任何方法可以使其更快,而没有:

  • 使用截断
  • 禁用或删除索引?

T-LOG已经在单独的磁盘上。

任何建议欢迎!

有帮助吗?

解决方案

您能做的就是这样的批次删除:

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable

xxx在哪里,例如50000

对此进行了修改,如果您想删除很高比例的行...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable

其他提示

您可以使用顶级子句轻松完成此操作:

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END

如果您无法使用截断,我同意将您的删除批量的建议批量的建议,并且我喜欢Drop/drop/创建其原创性的建议,但是我对您的问题中的以下评论感到好奇:

它基本上等同于截短表语句 - 除了我不允许使用截断

我猜测,这种限制的原因与需要批准直接截断表的安全性有关,这一事实使您可以截断除了您所关心的桌子以外的桌子。

假设是这种情况,我想知道是否创建了使用截断表的存储过程,并使用“执行为”将被视为可行的替代方案,可以赋予直接截断表所需的安全权。

希望这将为您带来所需的速度,同时还解决公司将帐户添加到DB_DDDLADMIN角色时可能存在的安全问题。

以这种方式使用存储过程的另一个优点是,存储过程本身可以锁定,以便仅允许特定帐户使用它。

如果由于某种原因这不是一个可接受的解决方案,并且您需要删除此表中的数据是需要每天/小时/等等的一次,我要求创建SQL代理作业以截断表每天预定时间。

希望这可以帮助!

除了截断。.仅在批处理中删除才能为您提供帮助。

您可以放下桌子并以所有的约束和索引来重新创建它。在Management Studio中,您可以选择脚本删除和创建表,因此它应该是一个微不足道的选项。但是,只有当您允许您执行DDL操作时,我认为这不是一个选择。

由于这个问题是如此重要的参考,因此我发布了此代码,它确实帮助我了解循环删除并在循环中传达以跟踪进度。

查询已从 这个 重复的问题。归功于 @RLF 对于查询基础。

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME 
DECLARE @currenttime DATETIME 

SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0  -- Total rows deleted so far is 0
SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()

WHILE @RowsTouched > 0
BEGIN
   DELETE TOP (@HowMany)
   FROM #DelTest 
   WHERE name LIKE '%sys%';

   SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
   SET @TotalRowCount = @TotalRowCount+@RowsTouched; -- Increment Total rows deleted count
   SET @currenttime = GETDATE();
   SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
   RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;
许可以下: CC-BY-SA归因
不隶属于 dba.stackexchange
scroll top