455 words
2 minutes
SQL Server Shell Games

SQL Partition SWITCH Operation#

With the power of the table partitioning SWITCH operation you can swap table metadata pointers instantly.

This can be used on any modern edition of sql server, even if table partioning is not supported. This is because under the hood every table is a single partition. With this you can quickly move data to an empty table and with some “shell games” instantly swap back to the old table.

I have used this many times to remove billions of rows by selecting out only the few hundred thousand that I wanted to keep into a new table and swapping table partition pointers. The swap is instant and there is little to no downtime.

Let’s walk through an example of the process.

-- create test set of tables
CREATE TABLE dbo.TEST1(id INT)
CREATE TABLE dbo.TEST2(id INT)
-- populate test1 with 10000 rows of data
DECLARE @i INT = 0
WHILE @i < 10000
BEGIN
INSERT INTO dbo.TEST1(id)
VALUES(@i)
SELECT @i += 1
END
-- view current state of things
SELECT * FROM dbo.TEST1
SELECT * FROM dbo.TEST2
-- switch data to second table
ALTER TABLE dbo.TEST1
SWITCH TO dbo.TEST2
-- view current state of things
SELECT * FROM dbo.TEST1
SELECT * FROM dbo.TEST2

Now that we have an idea of how this works, you can imagine that you have a table with billions of rows that you want to delete. DELETEs have to acquire a lock on the table at some level potentially preventing others from interacting with it. SELECTs however are much quicker and can be done in parallel without affecting others.

Below, we select out just the handful of rows that we want, truncate the original table, then swap the table pointers.

-- =========================
-- TRUNCATE TABLE SHELL GAME
-- =========================
-- move out set of data i want to keep
SELECT TOP 1000 * INTO dbo.TEMP_SHELL FROM dbo.TEST2
-- truncate orig table
TRUNCATE TABLE dbo.TEST2
-- move data metadata from shell to orig table
ALTER TABLE dbo.TEMP_SHELL
SWITCH TO dbo.TEST2
-- view current state of things
SELECT * FROM dbo.TEMP_SHELL
SELECT * FROM dbo.TEST2
-- remove shell table
DROP TABLE dbo.TEMP_SHELL
-- view current state of things
SELECT * FROM dbo.TEST1
SELECT * FROM dbo.TEST2
-- cleanup
DROP TABLE dbo.TEST1
DROP TABLE dbo.TEST2

This process has saved me countless hours of data processing and downtime.

I have used it in ETLs, ad-hoc table cleanups, as well as to create a simple data archiving process that moves old data by quarter into another table for historical reporting keeping the primary table lean.

This may not be such a concern now that Microsoft has opened up the table partitioning feature to all editions of SQL Server, but still useful for situations where the complexity of managing table partitioning outweighs the benifits.

~ SK

SQL Server Shell Games
https://www.kichka.dev/posts/sql-shell-games/
Author
Stephen Kichka
Published at
2025-12-20
License
CC BY-NC-SA 4.0