Summary: in this tutorial, you’ll learn how to partition an existing table in SQL Server using T-SQL.
Partitioning an existing table using T-SQL
The steps for partitioning an existing table are as follows:
- Create filegroups
- Create a partition function
- Create a partition scheme
- Create a clustered index on the table based on the partition scheme.
We’ll partition the sales.orders
table in the BikeStores
database by years.
Create filegroups
First, create two new file groups will store the rows with the order dates in 2016 and 2017:
ALTER DATABASE bikestores
ADD FILEGROUP salesorders_2016;
ALTER DATABASE bikestores
ADD FILEGROUP salesorders_2017;
Code language: SQL (Structured Query Language) (sql)
Second, map the filegroups with the physical files. Note that you need to have the D:\data
folder in the server before executing the following statements:
ALTER DATABASE bikestores
ADD FILE (
NAME = salesorders_2016,
FILENAME = 'D:\data\salesorders_2016.ndf',
SIZE = 10 MB,
MAXSIZE = UNLIMITED,
FILEGROWTH = 1024 KB
) TO FILEGROUP salesorders_2016;
ALTER DATABASE bikestores
ADD FILE (
NAME = salesorders_2017,
FILENAME = 'D:\data\salesorders_2017.ndf',
SIZE = 10 MB,
MAXSIZE = UNLIMITED,
FILEGROWTH = 1024 KB
) TO FILEGROUP salesorders_2017;
Code language: SQL (Structured Query Language) (sql)
Create a partition function
Create a partition function that accepts a date and returns three partitions:
CREATE PARTITION FUNCTION sales_order_by_year_function(date)
AS RANGE LEFT
FOR VALUES ('2016-12-31', '2017-12-31');
Code language: SQL (Structured Query Language) (sql)
Create a partition scheme
Create a partition scheme based on the sales_order_by_year_function
partition function:
CREATE PARTITION SCHEME sales_order_by_year_scheme
AS PARTITION sales_order_by_year_function
TO ([salesorders_2016], [salesorders_2017], [primary]);
Code language: SQL (Structured Query Language) (sql)
Create a clustered index on the partitioning column
The orders
table has the order_id
as the primary key. This primary key column is also included in a clustered index.
To partition the orders
table by the order_date
column, you need to create a clustered index for the order_date
column on the partition scheme sales_order_by_year_scheme
.
To do that, you need to change the clustered index that includes the order_id
column to a non-clustered index so that you can create a new clustered index that includes the order_date
column.
But the order_id
is referenced by a foreign key in the order_items
table. Therefore, you need to perform these steps:
First, remove the foreign key order_id
from the order_items
table:
ALTER TABLE [sales].[order_items]
DROP CONSTRAINT [FK__order_ite__order__3A81B327]
Code language: SQL (Structured Query Language) (sql)
Note that the constraint name FK__order_ite__order__3A81B327
may be different in your database.
Second, remove the primary key constraint from the orders
table:
ALTER TABLE [sales].[orders]
DROP CONSTRAINT [PK__orders__46596229EDE70106];
Code language: SQL (Structured Query Language) (sql)
Third, add the order_id
as a non-clustered primary key on the PRIMARY
partition:
ALTER TABLE [sales].[orders]
ADD PRIMARY KEY NONCLUSTERED([order_id] ASC)
ON [PRIMARY];
Code language: SQL (Structured Query Language) (sql)
Fourth, create a clustered index that includes the order_date
column:
CREATE CLUSTERED INDEX ix_order_date
ON [sales].[orders]
(
[order_date]
) ON [sales_order_by_year_scheme]([order_date])
Code language: SQL (Structured Query Language) (sql)
Fifth, drop the clustered index:
DROP INDEX ix_order_date
ON [sales].[orders];
Code language: SQL (Structured Query Language) (sql)
Finally, add the foreign key constraint back to the order_items
table:
ALTER TABLE [sales].[order_items]
WITH CHECK ADD FOREIGN KEY([order_id])
REFERENCES [sales].[orders] ([order_id])
ON UPDATE CASCADE
ON DELETE CASCADE;
Code language: SQL (Structured Query Language) (sql)
It’s better to run all the statements above in a transaction like this:
BEGIN TRANSACTION;
ALTER TABLE [sales].[order_items]
DROP CONSTRAINT [FK__order_ite__order__3A81B327];
ALTER TABLE [sales].[orders]
DROP CONSTRAINT [PK__orders__46596229EDE70106];
ALTER TABLE [sales].[orders] ADD PRIMARY KEY NONCLUSTERED
(
[order_id] ASC
) ON [PRIMARY];
CREATE CLUSTERED INDEX ix_order_date
ON [sales].[orders]
(
[order_date]
) ON [sales_order_by_year_scheme]([order_date]);
DROP INDEX ix_order_date
ON [sales].[orders];
ALTER TABLE [sales].[order_items]
WITH CHECK ADD FOREIGN KEY([order_id])
REFERENCES [sales].[orders] ([order_id])
ON UPDATE CASCADE
ON DELETE CASCADE;
COMMIT TRANSACTION;
Code language: SQL (Structured Query Language) (sql)
To check the number of rows in each partition, you use the following query:
SELECT
p.partition_number AS partition_number,
f.name AS file_group,
p.rows AS row_count
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(OBJECT_ID) = 'orders'
order by partition_number;
Code language: SQL (Structured Query Language) (sql)
Summary
- Create a clustered index on a partitioning column based on a partition scheme to partition an existing table.