To create a partitioned table in SQL Server, you must follow a specific sequence: create a partition function , create a partition scheme , and then apply that scheme to your table [1, 2]. This process splits data into logical segments to improve management and performance of large datasets [1, 2].
1. Create the Partition Function
This defines how the data is split based on a boundary value (like a date or ID) [1, 2].
- RANGE LEFT : The boundary value is the maximum value in the lower partition [1, 2].
- RANGE RIGHT : The boundary value is the minimum value in the higher partition (commonly used for dates) [1, 2, 3].
sql
-- Example: Partitioning by year using RANGE RIGHT
CREATE PARTITION FUNCTION pfSalesDate (datetime2)
AS RANGE RIGHT FOR VALUES ('2023-01-01', '2024-01-01', '2025-01-01');
-- This creates 4 partitions: < 2023, 2023, 2024, and >= 2025
2. Create the Partition Scheme
This maps the logical partitions created by the function to physical filegroups [1, 2]. You can map all partitions to a single filegroup (like PRIMARY) or distribute them across multiple disks [1, 2].
sql
-- Map all partitions to the PRIMARY filegroup
CREATE PARTITION SCHEME psSalesDate
AS PARTITION pfSalesDate
ALL TO ([PRIMARY]);
3. Create the Partitioned Table
Apply the scheme to the table during creation by specifying the partitioning column [1, 2].
sql
CREATE TABLE Sales (
SalesID INT IDENTITY(1,1),
OrderDate DATETIME2 NOT NULL,
Amount DECIMAL(18,2)
) ON psSalesDate (OrderDate); -- The table is now partitioned by OrderDate
Key Considerations
- Partition Elimination : SQL Server only reads the relevant partitions if your query filters by the partition key, significantly boosting performance [1, 2].
- Maintenance : Partitioning makes it easier to "switch" data in or out for archiving, or to truncate specific time periods without affecting the whole table [1, 2].
- Clustered Indexes : For an existing table, you can partition it by recreating the clustered index on the partition scheme [1, 2].
We can use the built-in Create Partition Wizard in SQL Server Management Studio (SSMS) to generate this script without writing manual code [1, 2].
Using the SSMS Partition Wizard
- Open the Wizard : Right-click your table, select Storage > Create Partition... [1, 2].
- Select Column: Choose your date column.
- Set Boundaries : On the Map Partitions page, click the Set Boundaries... button [1].
- Configure Range :
- Start Date :
2020-01-01 - End Date :
2030-01-01 - Date Range : Select Daily [1].
- Start Date :
- Script It : On the final page, select Script to New Query Window rather than running it immediately. This allows you to review the thousands of generated boundary lines [1, 2].
To maintain a partitioned table---especially one with daily partitions ---you primarily use Sliding Windowoperations. This allows you to add new days and archive old ones without moving data row-by-row.
1. Adding a New Partition (SPLIT)
To prepare for tomorrow's data, you "split" the last partition. Warning: The target filegroup must be empty or the operation will be slow.
sql
-- 1. Update the Scheme to tell it where the next partition goes
ALTER PARTITION SCHEME psDaily
NEXT USED [PRIMARY];
-- 2. Split the Function to add the new boundary (e.g., Jan 2, 2030)
ALTER PARTITION FUNCTION pfDaily()
SPLIT RANGE ('2030-01-02');
2. Removing Old Data (TRUNCATE or SWITCH)
If you want to delete a specific day's data instantly:
-
Option A: Truncate a specific partition (Fastest, SQL 2016+)
sqlTRUNCATE TABLE Sales WITH (PARTITIONS (1)); -- Removes all rows in Partition 1 -
Option B: Switch to an Archive table (Best for moving data to history)
sql-- Move Partition 1 data to an identical empty table ALTER TABLE Sales SWITCH PARTITION 1 TO Sales_Archive;
3. Merging Partitions (MERGE)
After archiving or deleting data, you "merge" the empty partition boundary to keep the total number of partitions manageable.
sql
-- Removes the boundary for Jan 1, 2020, merging that range into the next one
ALTER PARTITION FUNCTION pfDaily()
MERGE RANGE ('2020-01-01');
4. Checking Partition Health
Use this query to see exactly how many rows are in each day and which partition number they belong to:
sql
SELECT
p.partition_number,
f.name AS [PartitionFunction],
rv.value AS [BoundaryValue],
p.rows
FROM sys.partitions p
JOIN sys.indexes i ON p.object_id = i.object_id AND p.index_id = i.index_id
JOIN sys.partition_schemes s ON i.data_space_id = s.data_space_id
JOIN sys.partition_functions f ON s.function_id = f.function_id
LEFT JOIN sys.partition_range_values rv ON f.function_id = rv.function_id
AND p.partition_number = rv.boundary_id + 1
WHERE p.object_id = OBJECT_ID('Sales') AND i.index_id <= 1;
5. Index Maintenance
You can rebuild indexes for a single partition instead of the whole table, which saves time and transaction log space.
sql
ALTER INDEX PK_Sales ON Sales
REBUILD PARTITION = 500; -- Rebuilds only the 500th day/partition