In the last post on this subject I talked about table partitioning and aligned indexes. This time I would like to discuss table partitioning and non-aligned indexes. But first I wanted to give you a little code that would answer the very last pieces of the summary in the last post. In the summary I asked you to take a look at the indexes we created to find more information about them. If you looked at the sys.index_columns catalog view, you would have noticed that the nonclustered, aligned index also included the partitioning column.
–Review the indexes just created
SELECT i.[name] AS ‘Index Name’
,i.index_id AS ‘Index ID’
,i.type_desc AS ‘Index Type’
,ic.index_column_id AS ‘Column’
,c.[name] AS ‘Column Name’
,ic.key_ordinal AS ‘Key Column’
,ic.is_included_column AS ‘INCLUDE Column’
,ic.partition_ordinal AS ‘Partitioning Column’–partitioning column added to index or part of key
FROM sys.indexes i
INNER JOIN sys.index_columns ic
ON i.[object_id] = ic.[object_id]
AND i.index_id = ic.index_id
INNER JOIN sys.columns c
ON ic.[object_id] = c.[object_id]
AND ic.column_id = c.column_id
WHERE i.[object_id] = OBJECT_ID(‘partitionDate’)
ORDER BY i.name, i.index_id,ic.index_column_id
My output
Index Name Index ID Index Type Column Column Name Key Column INCLUDE Column Partitioning Column
cl_partitionDate_colDate 1 CLUSTERED 1 colDate 1 0 1
ncl_partitionDate_colSession_1 2 NONCLUSTERED 1 colSession 1 0 0
ncl_partitionDate_colSession_1 2 NONCLUSTERED 2 colDesc 0 1 0
ncl_partitionDate_colSession_1 2 NONCLUSTERED 3 colDate 0 0 1
If you look at the reformatted output, you will notice that the nonclustered index has the one index key we defined (colSession), one INCLUDED Column (colDesc), and the partition column (ColDate). SQL Server added the colDate to the index in order for the index to be able to eliminate partitions during queries.
Let’s move forward and talk about non-aligned indexes. A non-aligned index is one that does not share the same partitioning design as the table which contains the data. You achieve non-aligned indexes by creating the index and using a different function and scheme when doing so. While there are several disadvantages to having non-aligned indexes on a partitioned table, there are several advantages that will be explained in the third part of this series when we discuss partitioned indexes and performance.
Note: Having non-aligned indexes on a table will prevent you from switching partitions from one table to another.
Let’s take a look at how to create a non-aligned index.
SET NOCOUNT ON
GO
–Create table on main DateRange partition
IF OBJECT_ID (‘partitionDate’) IS NOT NULL
DROP TABLE partitionDate
GO
CREATE TABLE partitionDate
(colDate DATETIME
,colSession INT
,colDesc VARCHAR(100)
)
GO
–Insert data into table
DECLARE @loop INT
SET @loop = 5000
WHILE @loop > 0
BEGIN
INSERT INTO partitionDate VALUES (‘20060301’,1,‘20060301-1’ )
INSERT INTO partitionDate VALUES (‘20060401’,1,‘20060401-1’ )
INSERT INTO partitionDate VALUES (‘20060501’,1,‘20060501-1’ )
INSERT INTO partitionDate VALUES (‘20060601’,1,‘20060601-1’ )
INSERT INTO partitionDate VALUES (‘20060701’,1,‘20060701-1’ )
INSERT INTO partitionDate VALUES (‘20060801’,1,‘20060801-1’ )
INSERT INTO partitionDate VALUES (‘20060901’,1,‘20060901-1’ )
INSERT INTO partitionDate VALUES (‘20061001’,1,‘20061001-1’ )
INSERT INTO partitionDate VALUES (‘20061101’,1,‘20061101-1’ )
INSERT INTO partitionDate VALUES (‘20061201’,1,‘20061201-1’ )
INSERT INTO partitionDate VALUES (‘20070101’,1,‘20070101-1’ )
INSERT INTO partitionDate VALUES (‘20070201’,1,‘20070201-1’ )
INSERT INTO partitionDate VALUES (‘20070301’,1,‘20070301-1’ )
INSERT INTO partitionDate VALUES (‘20060301’,2,‘20060301-2’ )
INSERT INTO partitionDate VALUES (‘20060401’,2,‘20060401-2’ )
INSERT INTO partitionDate VALUES (‘20060501’,2,‘20060501-2’ )
INSERT INTO partitionDate VALUES (‘20060601’,2,‘20060601-2’ )
INSERT INTO partitionDate VALUES (‘20060701’,2,‘20060701-2’ )
INSERT INTO partitionDate VALUES (‘20060801’,2,‘20060801-2’ )
INSERT INTO partitionDate VALUES (‘20060901’,2,‘20060901-2’ )
INSERT INTO partitionDate VALUES (‘20061001’,2,‘20061001-2’ )
INSERT INTO partitionDate VALUES (‘20061101’,2,‘20061101-2’ )
INSERT INTO partitionDate VALUES (‘20061201’,2,‘20061201-2’ )
INSERT INTO partitionDate VALUES (‘20070101’,2,‘20070101-2’ )
INSERT INTO partitionDate VALUES (‘20070201’,2,‘20070201-2’ )
INSERT INTO partitionDate VALUES (‘20070301’,2,‘20070301-2’ )
INSERT INTO partitionDate VALUES (‘20060301’,3,‘20060301-3’ )
INSERT INTO partitionDate VALUES (‘20060401’,3,‘20060401-3’ )
INSERT INTO partitionDate VALUES (‘20060501’,3,‘20060501-3’ )
INSERT INTO partitionDate VALUES (‘20060601’,3,‘20060601-3’ )
INSERT INTO partitionDate VALUES (‘20060701’,3,‘20060701-3’ )
INSERT INTO partitionDate VALUES (‘20060801’,3,‘20060801-3’ )
INSERT INTO partitionDate VALUES (‘20060901’,3,‘20060901-3’ )
INSERT INTO partitionDate VALUES (‘20061001’,3,‘20061001-3’ )
INSERT INTO partitionDate VALUES (‘20061101’,3,‘20061101-3’ )
INSERT INTO partitionDate VALUES (‘20061201’,3,‘20061201-3’ )
INSERT INTO partitionDate VALUES (‘20070101’,3,‘20070101-3’ )
INSERT INTO partitionDate VALUES (‘20070201’,3,‘20070201-3’ )
INSERT INTO partitionDate VALUES (‘20070301’,3,‘20070301-3’ )
SET @loop = @loop – 1
END
GO
–Create partition function for session
CREATE PARTITION FUNCTION [pfSessionRange] (INT)
AS RANGE RIGHT FOR VALUES (1, 2, 3);
GO
–Create partition scheme for session
CREATE PARTITION SCHEME psFunctionRange
AS PARTITION [pfSessionRange]
TO ([PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY]);
GO
–Create new non-aligned index
CREATE NONCLUSTERED INDEX ncl_partitionDate_colSession_21 ON partitionDate(colSession) INCLUDE (colDesc)
ON psFunctionRange (colSession)
GO
Once we create the index, let’s look at the index information using the code from above. You will notice that the partitioning column is now the index key column.
Index Name Index ID Index Type Column Column Name Key Column INCLUDE Column Partitioning Column
ncl_partitionDate_colSession_21 2 NONCLUSTERED 1 colSession 1 0 1
ncl_partitionDate_colSession_21 2 NONCLUSTERED 2 colDesc 0 1 0
What does the nonclustered index look like when the table has been partitioned but no clustered index exists? Recreate the table from above but this time partition the table with the same format as before.
–Create main partition function for date
CREATE PARTITION FUNCTION [pfDateRange] (DATETIME)
AS RANGE RIGHT FOR VALUES ( ‘20060301’, ‘20060401’,
‘20060501’, ‘20060601’, ‘20060701’, ‘20060801’,
‘20060901’, ‘20061001’, ‘20061101’, ‘20061201’,‘20070101’,‘20070201’,‘20070301’);
GO
–Create partition scheme for date
CREATE PARTITION SCHEME psDateRange
AS PARTITION [pfDateRange]
TO ([PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY],[PRIMARY]);
GO
–Create table on main DateRange partition
CREATE TABLE partitionDate
(colDate DATETIME
,colSession INT
,colDesc VARCHAR(100)
) ON psDateRange(colDate)
GO
Now, recreate the non-aligned index.
–Create new non-aligned index
CREATE NONCLUSTERED INDEX ncl_partitionDate_colSession_21 ON partitionDate(colSession) INCLUDE (colDesc)
ON psFunctionRange (colSession)
GO
Take a look at the non-aligned again. You will notice that the heap is partitioned by colDate but the non-aligned index still only has the two columns we defined in the CREATE INDEX statement, the partition column of the table is not included in the index since the index key is the partition column of the index.
Note: This will stay the same even if you created a clustered index on the table.
I know, this post doesn’t have a lot of great information in it but I wanted to use it to set up the next post in this series. The next post will cover how aligned and non-aligned indexes affect the performance of SELECT queries against the table and its indexes.