Below is an example script that reduces logging the FULL recovery model using SWITCH
and TRUNCATE
. The SWITCH
is a fast meta data only operation. The space deallocation performed by TRUNCATE
is done by an asynchronous background thread with larger tables (64MB+) so it is also fast and reduces logging greatly compared to DELETE
;
A transaction is used to ensure all-or-none behavior and a schema modification lock is held for the duration of the transaction to quiesce data modifications during the process.
Below is the transaction log space used before and after the process by the example with 1M rows initially and 50K retained:
+--------+---------------+--------------------+
| | Log Size (MB) | Log Space Used (%) |
+--------+---------------+--------------------+
| Before | 1671.992 | 27.50415 |
| After | 1671.992 | 30.65533 |
+--------+---------------+--------------------+
Test setup:
--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
Example script:
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