我需要从生产中的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。我也需要一些解释。任何人都可以帮助我
答案 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)
我理解你的问题,因为我曾经历过一次。 以下链接也可能对您有所帮助。