SQL Server Partition Existing Table

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.
Was this tutorial helpful?