哪一个是最佳实践?批量删除或前10000行

时间:2014-02-12 05:15:20

标签: sql-server performance

我需要从生产中的25个表中删除630万条记录。我有以下两个查询,我不知道哪一个最好?

delete  jc 
from Jtable jc
join J1Table j 
on j.JobId = jc.JobId 
join nonJobReProcess n
on n.jobid = j.JobId

while exists (select top 1 * from dbo.Jtable jc (nolock)
join J1Table j (nolock)
on j.JobId = jc.JobId 
join nonJobReProcess  n  (nolock)
on n.jobid = j.JobId)
begin 

delete  top (10000) jc 
from dbo.Jtable jc (nolock)
join J1Table j (nolock)
on j.JobId = jc.JobId 
join nonJobReProcess n  (nolock)
on n.jobid = j.JobId

end 

我正在使用sql server 2008 R2。我也需要一些解释。任何人都可以帮助我

4 个答案:

答案 0 :(得分:2)

问题可能更多是关于删除期间数据库的整体并发性 - 批量删除可能是后台清理过程的一部分,并且删除对整个系统的影响比性能更重要。批量删除自己。

在大约5000 locks,SqlServer将开始考虑升级到表锁,这将阻止表的并发写入程序(例如插入器),直到删除完成。这是在循环批量删除中考虑的方案。

另一个考虑因素是记录。如果您有简单的恢复模式,那么batching the deletes会保持日志大小不变,但您应该在每批后添加CHECKPOINT

一般情况下,单行delete命令应该是删除性能的默认方法,除非并发性很重要。

此外,使用表上的nolock优化器提示进行删除没有意义 - 删除需要独占锁。

delete  top (10000) jc 
from dbo.Jtable jc -- (nolock) - no point.

答案 1 :(得分:1)

如果您尝试在一个批处理中删除6.3M行,则必须对其进行全部处理,并在提交之前进行记录。您的日志文件将快速增长,并损害性能。这里的最佳做法是批量删除。如果你在生产服务器上,可能很高兴添加一个waitfor来给服务器一些时间来呼吸。

WAITFOR DELAY '00:00:10'

此外,删除操作会忽略NOLOCK提示。

这是一个循环,直到完成。

DECLARE @BATCHCOUNT INT
SET @BATCHCOUNT = 10000 -- SET INITIAL COUNT HERE...
WHILE @BATCHCOUNT > 0
BEGIN
   DELETE TOP(@BATCHCOUNT) FROM MYTABLE
   SET @BATCHCOUNT = @@ROWCOUNT
   WAITFOR DELAY '00:00:05'
END

答案 2 :(得分:1)

这里要考虑的一点是,在生产中,您可能无法简单地设置恢复模式。如果是这样,那么我建议您进一步查看要删除的内容,以及是否会导致填写tempdb或日志文件的问题。

我最近创建了一个类似的大型删除过程,它会填充tempdb并记录几次,所以我把它创建成一个作业,它会检查每个批次后的当前空间使用情况,并在剩余空间接近时中止在下一次备份之前,生产仍可以舒适地运行的水平。然后下次再从那里拿起。

下面是如何从tempdb和log收集保留空间和可用空间的示例,不确定它的整体可靠性,但它在SQL Server 2008/2012中迄今为止都有效。当然,这不会告诉您如何你的SQL Server的硬盘空间有多大空间来增加保留的log / tempdb空间(我刚刚发现了老式的方式,然后继续看了)。

DECLARE @LOGSTATS TABLE (DBNAME VARCHAR(256), LOGSIZE_MB DEC (32,2)
    , [LOGSPACEUSED_%] DEC(32,2), STATUS BIT)

INSERT INTO @LOGSTATS
EXEC('DBCC SQLPERF(logspace) WITH NO_INFOMSGS')

SELECT DB_NAME() DBName
    , CAST((SELECT (LOGSIZE_MB-(LOGSIZE_MB*([LOGSPACEUSED_%]/100)))/1024
        FROM @LOGSTATS WHERE DBNAME = DB_NAME()) AS DEC(18,2))
    AS Log_free_GB
    , (SELECT CAST((CAST((size*8) AS DEC(18,2))/1024)/1024 AS DEC(18,2)) Log_reserved_GB
        FROM sys.master_files WHERE DB_NAME(database_id) = DB_NAME() AND type_desc = 'LOG')
    AS Log_reserved_GB
    , (SELECT CAST((SUM(unallocated_extent_page_count)*1.0/128)/1024 AS DEC(18,2)) AS FreeSpaceGB
        FROM tempdb.sys.dm_db_file_space_usage)
    AS Tempdb_free_GB
    , (SELECT CAST(SUM(size*1.0/128)/1024 AS DEC(18,2)) TDspace
        FROM tempdb.sys.database_files WHERE type_desc = 'ROWS')
    AS Tempdb_reserved_GB

基本上,如果您可以假设生产tempdb和日志空间已经增长到它们所支持的内容,那么您可以将删除批处理放入while循环中。在while循环中,您的条件是继续运行,直到可用空间小于例如50 GB(当然取决于您的数据库和环境)。

当然,这是一个定制的解决方案,因此您需要了解它如何适用于您的方案。

答案 3 :(得分:0)

我理解你的问题,因为我曾经历过一次。 以下链接也可能对您有所帮助。

Please have a look at it