使用SQL Server 2005。
我正在执行巨大的DELETE FROM而没有where子句。它基本上等效于TRUNCATE TABLE语句-除了不允许使用TRUNCATE。问题是表很大-一千万行,而且要花一个多小时才能完成。有没有什么办法可以使其更快而没有:
- 使用截断
- 禁用或删除索引?
t日志已经在单独的磁盘上。
任何建议欢迎!
使用SQL Server 2005。
我正在执行巨大的DELETE FROM而没有where子句。它基本上等效于TRUNCATE TABLE语句-除了不允许使用TRUNCATE。问题是表很大-一千万行,而且要花一个多小时才能完成。有没有什么办法可以使其更快而没有:
t日志已经在单独的磁盘上。
任何建议欢迎!
Answers:
您可以做的是批量删除,如下所示:
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
如果您无法使用TRUNCATE,我同意将删除操作批量处理为可管理块的建议,并且我喜欢drop / create建议的独创性,但是我对您的问题中的以下评论感到好奇:
它基本上等效于TRUNCATE TABLE语句- 除非不允许使用TRUNCATE
我猜想这种限制的原因与直接截断表所需的安全性有关,并且它允许您截断与您关心的表不同的表。
假设是这种情况,我想知道是否创建了一个使用TRUNCATE TABLE并使用“ EXECUTE AS”的存储过程,而不是提供直接截断该表所必需的安全权限的可行选择。
希望这可以为您提供所需的速度,同时还可以解决您公司将帐户添加到db_ddladmin角色时可能遇到的安全问题。
以这种方式使用存储过程的另一个优点是,存储过程本身可以被锁定,从而仅允许特定帐户使用它。
如果由于某种原因这不是可接受的解决方案,并且您需要每天/每小时/等一次删除该表中的数据,我将请求创建一个SQL Agent作业以截断该表在每天的预定时间。
希望这可以帮助!
由于此问题是如此重要,因此我将发布此代码,它确实帮助我了解了使用循环进行删除以及在循环内进行消息传递以跟踪进度的过程。
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;