Skip to main content

Table Partitioning

Partitioning divides a large table into smaller physical segments based on a column value (e.g., date). Queries can then skip irrelevant partitions (partition elimination), improving performance.

Steps to Partition a Table

Step 1: Create a Partition Function

Defines the boundary values that split data into ranges.

CREATE PARTITION FUNCTION PartitionByYear (DATE)
AS RANGE LEFT FOR VALUES ('2023-12-31', '2024-12-31', '2025-12-31');

This creates 4 partitions: ≤2023, 2024, 2025, and ≥2026.

Step 2: Create Filegroups

Each partition maps to a filegroup.

ALTER DATABASE SalesDB ADD FILEGROUP FG_2023;
ALTER DATABASE SalesDB ADD FILEGROUP FG_2024;
ALTER DATABASE SalesDB ADD FILEGROUP FG_2025;
ALTER DATABASE SalesDB ADD FILEGROUP FG_2026;

Step 3: Create Data Files

Map physical files to filegroups.

ALTER DATABASE SalesDB ADD FILE (
NAME = P_2023,
FILENAME = 'C:\...\P_2023.ndf'
) TO FILEGROUP FG_2023;
-- Repeat for each filegroup

Step 4: Create a Partition Scheme

Maps the partition function to filegroups.

CREATE PARTITION SCHEME SchemePartitionByYear
AS PARTITION PartitionByYear
TO (FG_2023, FG_2024, FG_2025, FG_2026);

Step 5: Create the Partitioned Table

CREATE TABLE Sales.Orders_Partitioned (
OrderID INT,
OrderDate DATE,
Sales INT
) ON SchemePartitionByYear (OrderDate);

Step 6: Insert Data

INSERT INTO Sales.Orders_Partitioned VALUES (1, '2023-05-15', 100);
INSERT INTO Sales.Orders_Partitioned VALUES (2, '2024-07-20', 50);
INSERT INTO Sales.Orders_Partitioned VALUES (3, '2025-12-31', 20);
INSERT INTO Sales.Orders_Partitioned VALUES (4, '2026-01-01', 100);

Step 7: Verify

SELECT
p.partition_number AS PartitionNumber,
f.name AS Filegroup,
p.rows AS RowCount
FROM sys.partitions p
JOIN sys.destination_data_spaces dds ON p.partition_number = dds.destination_id
JOIN sys.filegroups f ON dds.data_space_id = f.data_space_id
WHERE OBJECT_NAME(p.object_id) = 'Orders_Partitioned';

Partition Elimination

When filtering by the partition column, SQL Server reads only the relevant partition.

-- Only scans the 2025 and 2026 partitions
SELECT *
FROM Sales.Orders_Partitioned
WHERE OrderDate IN ('2025-12-31', '2026-01-01');

When to Partition

ScenarioPartition?
Table has millions+ rowsYes
Frequent date-range queriesYes
Small tables (under 100K rows)No — indexes are sufficient
Need to archive old dataYes — drop/switch partitions