执行交易时为 Update/Delete/Insert 锁定 table
Lock table for Update/Delete/Insert when executing a transaction
我正在尝试使用 How to delete large data of table in SQL without log?
将我的 DELETE 语句转换为 TRUNCATE
这是我正在尝试的,
-- Move recent records from Main table to a Temp table
-- TRUNCATE the Main table
-- Return back data from Temp table to Main table
在此期间,我想在我的 Main table 上停止任何 INSERT/UPDATE/DELETE 语句(直到 TRUNCATE 语句 运行)到 运行 因为如果我允许那么我们可能在 TRUNCATE 期间丢失了一些数据。
尝试使用事务:
BEGIN TRANSACTION
SELECT TOP 1 *
FROM table_name
WITH (TABLOCK, HOLDLOCK)
-- do your stuff
COMMIT
TRUNCATE
statement acquires SCH-M
lock 这意味着它创建了一个 Schema Modification lock
Second type of the lock is schema modification lock – SCH-M. This lock
type is acquired by sessions that are altering the metadata and live
for duration of transaction. This lock can be described as
super-exclusive lock and it’s incompatible with any other lock types
including intent locks
Locking in Microsoft SQL Server (Part 13 – Schema locks)
在此期间,更新、select 和删除语句将等待 table 截断操作。因此,CRUD 操作将自动停止,直到 TRUNCATE 语句完成。
下面是一个示例脚本,它使用 SWITCH
和 TRUNCATE
减少了完整恢复模型的日志记录。 SWITCH
是一个快速的元数据操作。 TRUNCATE
执行的 space 释放是由具有更大表 (64MB+) 的异步后台线程完成的,因此与 DELETE
;
相比,它也很快并且大大减少了日志记录
事务用于确保全或-none 行为,并在事务期间持有架构修改锁以停止进程中的数据修改。
下面是示例处理前后使用的事务日志space,最初有 1M 行,保留了 50K 行:
+--------+---------------+--------------------+
| | Log Size (MB) | Log Space Used (%) |
+--------+---------------+--------------------+
| Before | 1671.992 | 27.50415 |
| After | 1671.992 | 30.65533 |
+--------+---------------+--------------------+
测试设置:
--example main table
CREATE TABLE dbo.Main(
MainID int NOT NULL CONSTRAINT PK_Main PRIMARY KEY
, MainData char(1000) NOT NULL
);
--staging table with same schema and indexes as main table
CREATE TABLE dbo.MainStaging(
MainID int NOT NULL CONSTRAINT PK_MainStaging PRIMARY KEY
, MainData char(1000) NOT NULL
);
--load 1M rows into main table for testing
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t1k AS (SELECT 0 AS n FROM t10 AS a CROSS JOIN t10 AS b CROSS JOIN t10 AS c)
,t1g AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS num FROM t1k AS a CROSS JOIN t1k AS b CROSS JOIN t1k AS c)
INSERT INTO dbo.Main WITH(TABLOCKX) (MainID, MainData)
SELECT num, CAST(num AS char(1000))
FROM t1g
WHERE num <= 1000000;
GO
示例脚本:
SET XACT_ABORT ON; --ensures transaction is rolled back immediately even if script is cancelled
BEGIN TRY
BEGIN TRAN;
--truncate in same transaction so entire script can be safely rerun
TRUNCATE TABLE dbo.MainStaging;
--ALTER TABLE will block other activity until committed due to schema modification lock
--main table will be empty after switch
ALTER TABLE dbo.Main SWITCH TO dbo.MainStaging;
--keep 5% of rows
INSERT INTO dbo.Main WITH(TABLOCKX) (MainID, MainData)
SELECT MainID, MainData
FROM dbo.MainStaging
WHERE MainID > 950000;
COMMIT;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK;
THROW;
END CATCH;
GO
我正在尝试使用 How to delete large data of table in SQL without log?
将我的 DELETE 语句转换为 TRUNCATE这是我正在尝试的,
-- Move recent records from Main table to a Temp table
-- TRUNCATE the Main table
-- Return back data from Temp table to Main table
在此期间,我想在我的 Main table 上停止任何 INSERT/UPDATE/DELETE 语句(直到 TRUNCATE 语句 运行)到 运行 因为如果我允许那么我们可能在 TRUNCATE 期间丢失了一些数据。
尝试使用事务:
BEGIN TRANSACTION
SELECT TOP 1 *
FROM table_name
WITH (TABLOCK, HOLDLOCK)
-- do your stuff
COMMIT
TRUNCATE
statement acquires SCH-M
lock 这意味着它创建了一个 Schema Modification lock
Second type of the lock is schema modification lock – SCH-M. This lock type is acquired by sessions that are altering the metadata and live for duration of transaction. This lock can be described as super-exclusive lock and it’s incompatible with any other lock types including intent locks
Locking in Microsoft SQL Server (Part 13 – Schema locks)
在此期间,更新、select 和删除语句将等待 table 截断操作。因此,CRUD 操作将自动停止,直到 TRUNCATE 语句完成。
下面是一个示例脚本,它使用 SWITCH
和 TRUNCATE
减少了完整恢复模型的日志记录。 SWITCH
是一个快速的元数据操作。 TRUNCATE
执行的 space 释放是由具有更大表 (64MB+) 的异步后台线程完成的,因此与 DELETE
;
事务用于确保全或-none 行为,并在事务期间持有架构修改锁以停止进程中的数据修改。
下面是示例处理前后使用的事务日志space,最初有 1M 行,保留了 50K 行:
+--------+---------------+--------------------+
| | Log Size (MB) | Log Space Used (%) |
+--------+---------------+--------------------+
| Before | 1671.992 | 27.50415 |
| After | 1671.992 | 30.65533 |
+--------+---------------+--------------------+
测试设置:
--example main table
CREATE TABLE dbo.Main(
MainID int NOT NULL CONSTRAINT PK_Main PRIMARY KEY
, MainData char(1000) NOT NULL
);
--staging table with same schema and indexes as main table
CREATE TABLE dbo.MainStaging(
MainID int NOT NULL CONSTRAINT PK_MainStaging PRIMARY KEY
, MainData char(1000) NOT NULL
);
--load 1M rows into main table for testing
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t1k AS (SELECT 0 AS n FROM t10 AS a CROSS JOIN t10 AS b CROSS JOIN t10 AS c)
,t1g AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS num FROM t1k AS a CROSS JOIN t1k AS b CROSS JOIN t1k AS c)
INSERT INTO dbo.Main WITH(TABLOCKX) (MainID, MainData)
SELECT num, CAST(num AS char(1000))
FROM t1g
WHERE num <= 1000000;
GO
示例脚本:
SET XACT_ABORT ON; --ensures transaction is rolled back immediately even if script is cancelled
BEGIN TRY
BEGIN TRAN;
--truncate in same transaction so entire script can be safely rerun
TRUNCATE TABLE dbo.MainStaging;
--ALTER TABLE will block other activity until committed due to schema modification lock
--main table will be empty after switch
ALTER TABLE dbo.Main SWITCH TO dbo.MainStaging;
--keep 5% of rows
INSERT INTO dbo.Main WITH(TABLOCKX) (MainID, MainData)
SELECT MainID, MainData
FROM dbo.MainStaging
WHERE MainID > 950000;
COMMIT;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK;
THROW;
END CATCH;
GO