Why SQL Server Tuning Advisor proposes to add PRIMARY KEY to included columns of index?
-
29-04-2021 - |
Question
I have seen this a number of times, when I run some analysis in SQL Server DataBase Engine Tuning Advisor it suggest me to create indexes like:
CREATE NONCLUSTERED INDEX [_index] ON [dbo].[SomeTable]
(
[Column1] ASC,
[Column2] ASC,
[Column3] ASC
)
INCLUDE ([PrimaryKeyColumn])
Does it really matter to include primary key (clustered index) column to included columns list? I always think that it is included by default as link to original row. Am I wrong?
Update: I think it is also important to note that it proposes such index for query like: SELECT [PrimaryKeyColumn] FROM [dbo].[SomeTable] WHERE ...[Conditions]... and it really influences performance and execution plan. So as far as I understand index doesn't contain really 'clustered index', but just some link to row. Is it so?
Solution
You can create the index with or without the INCLUDE: SQL Server will ignore it if the PrimaryKeyCol is the clustered index. That is, it won't store the clustered index value twice
For completeness, I probably would in case I ever change the clustered index
Edit:
I've observed via size that SQL Server deals with this intelligently
This is not as scientific as Kalen Delaney's More About Nonclustered Index Keys
DROP TABLE IncludeTest;
GO
CREATE TABLE IncludeTest (
BadClusteredKey uniqueidentifier DEFAULT NEWID() PRIMARY KEY,
OtherCol AS CHECKSUM(BadClusteredKey) % 10000,
Filler char(200) NOT NULL DEFAULT 'a and lots of spaces'
);
GO
INSERT IncludeTest (Filler) VALUES (DEFAULT);
GO
INSERT IncludeTest (Filler) SELECT Filler FROM IncludeTest
GO 20
SELECT COUNT(*) FROM IncludeTest;
EXEC sp_spaceused 'IncludeTest', 'true'
GO -- 400680 KB, 1920 KB
CREATE INDEX IX_OtherCol1 ON IncludeTest (OtherCol);
GO
EXEC sp_spaceused 'IncludeTest', 'true'
GO -- 400680 KB, 29024 KB KB
DROP INDEX IncludeTest.IX_OtherCol1
GO
EXEC sp_spaceused 'IncludeTest', 'true'
GO -- 400680 KB, 1920 KB
CREATE INDEX IX_OtherCol2 ON IncludeTest (OtherCol) INCLUDE (BadClusteredKey);
EXEC sp_spaceused 'IncludeTest', 'true'
GO -- 400680 KB, 29024 KB
DROP INDEX IncludeTest.IX_OtherCol2
GO
EXEC sp_spaceused 'IncludeTest', 'true'
GO -- 400680 KB, 1920 KB
OTHER TIPS
I think Tuning advisor detect you query and found that you have PrimaryKeyColumn in you select cause and you have Column1, Column2 and Column3 in where cause.
Tuning advisor think that.... if you index include PrimaryKeyColumn in the index SQL don't need to wast overhead to look up to get PrimaryKeyColumn data in data page(table data page). SQL engine would be able to take PrimaryKeyColumn value from index directly for you query. it save time..
Note that: There are bad side of the index(include column). at http://msdn.microsoft.com/en-us/library/ms190806.aspx contains useful information that might help you make decision.