The table contains about 100m rows of data per year. I wanted to remove all data except for last 2 years of data. Data starts from 2017.
To do so, instead of simple delete, I used while loop for delete top 10,000 rows.
During the process, I was wondering, how can I observe the best number of rows to be deleted per loop?
How can I do so without leaving trail in transaction log?
I want to loop delete with most efficiency without burdening the database.

DECLARE
@TargetDT VARCHAR(10),@Counter INT = 1
SET @TargetDT = '2018-01-01'

WHILE (@Counter <= 100)
BEGIN
delete top(10000) from  MYTABLE where DATE_COLUMN < @TargetDT 
SET @Counter = @Counter + 1
END

我try 了每个循环要删除的不同行数:500、1000、2000、5000、10000

推荐答案

The best method is not to delete at all.这可能会非常慢,导致大量事务日志(log)增长,如果您try 将日志(log)设置为SHRINK,则可能会遇到更多问题.

相反,将需要的数据复制到一个新表中,然后执行切换并删除另一个表.

做切换的最好方法不是使用sp_rename,而是使用ALTER TABLE SWITCH.为此,最好使用两个单独的临时表,它们的定义与主表完全相同.

将您的数据库切换到大容量日志(log),这意味着大型插入获得的日志(log)记录要少得多.使用INSERT上的TABLOCK提示进行最小日志(log)记录,以及并行插入.

CREATE TABLE Staging1 (
  -- exact same columns, types, nullable
  -- exact same primary, unique, foreign keys, check constraints
);

CREATE TABLE Staging2 (
  -- exact same columns, types, nullable
  -- exact same primary, unique, foreign keys, check constraints
);

INSERT Staging2 WITH (TABLOCK)
  (ColumsHere)
SELECT ColumnsHere
FROM YourTable
WHERE whatever;  --all data to keep

如果您经常插入,那么您需要找到一种在复制时保持新表同步的方法(可能使用触发器).您也可以使用SNAPSHOT ISOLATION来避免挡住旧桌子.


现在您可以进行切换了

SET XACT_ABORT, NOCOUNT ON;      -- force immediate rollback if session is killed

BEGIN TRAN;

ALTER TABLE YourTable SWITCH TO Staging1
WITH ( WAIT_AT_LOW_PRIORITY ( MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = BLOCKERS ));
-- not strictly necessary to use WAIT_AT_LOW_PRIORITY but better for blocking
-- use SELF instead of BLOCKERS to kill your own session

ALTER TABLE Staging2 SWITCH TO YourTable
WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 0 MINUTES, ABORT_AFTER_WAIT = BLOCKERS));
-- force blockers off immediately

COMMIT TRAN;

最后删除或删除旧数据

TRUNCATE TABLE Staging1;

所有这些切换都完全是元数据的,而且非常非常快(大约几毫秒).它只占极少量的伐木量.您还可以通过为新的数据大小重新构建索引而受益.


如果您的磁盘上没有足够的空间,您可以添加一个临时磁盘(内部/外部SSD驱动器等),并将FILE添加到同一文件组中.然后,在截断旧数据之后,可以从文件组as explained here中删除该文件.不要创建新的文件组,在这种情况下,此代码将不起作用.

Sql相关问答推荐

如何根据SQL中的列条件获取下一个时间戳?

将SEMI JOIN、ANTI JOIN转换为非连接SQL

更新PostgreSQL 15中的JSON值

从日期开始向前填充重复项

基于多列比较连接两个表

在UNION查询中查找MIN

最小非重复集的SQL查询

PostgreSQL中递归CTE查询的故障过滤

根据具有特定值的 ID 创建自定义组

SQL Server中使用min()和max()从选定的特定值id表中删除不必要的时间

清理 XML 数据

如何在 case 语句中使用聚合?

一次 Select 语句中按组累计的SQL累计数

基于字符串的SQL查询

计数时如何为所有时间间隔返回 0 而不是什么都不返回

使用 PL/PGSQL 函数 Select 返回多条记录

SQL日期比较用例;月初至今的报告

面对来自以下两个代码的不同输出

BigQuery 错误:SELECT 列表表达式引用 esthetician.LICENSE_TYPE,它既未在 [49:8] 分组也未聚合

如何使用子查询锁定此查询中的选定行?