Sql-server – Non-clustered foreign key index recommendation

foreign-keysindexingsql serversql-server-2012

I have several tables in my database that are parent child relationships. For example:

CREATE TABLE [dbo].[cntnr_header] 
(
    [cntnr_id]            [dbo].[uid]     NOT NULL,
    CONSTRAINT [pk_cntnr_header] PRIMARY KEY CLUSTERED ([cntnr_id] ASC),
);

CREATE TABLE [dbo].[cntnr_content] 
(
    [cntnr_content_id]  [dbo].[uid]       NOT NULL,
    [cntnr_id]          [dbo].[uid]       NOT NULL,
    CONSTRAINT [pk_cntnr_content] 
       PRIMARY KEY CLUSTERED ([cntnr_content_id] ASC),
    CONSTRAINT [fk_cntnr_content_cntnr_header] 
       FOREIGN KEY ([cntnr_id]) 
       REFERENCES [dbo].[cntnr_header] ([cntnr_id]),
);

Currently as you can see there is not an index on the foreign key cntnr_id in the table cntnr_content. I ran the tuning wizard and I actually saw it suggest a non-clustered index be added for both cntnr_content_id and cntnr_id on the table cntnr_content. I don't really understand this because cntnr_content_id is already a clustered index. Why would it recommend an index like this?

CREATE NONCLUSTERED INDEX [_dta_index_cntnr_content_7_821577965__K1_K2] ON [dbo].[cntnr_content]
(
    [cntnr_content_id] ASC,
    [cntnr_id] ASC
)WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]

I would think that I probably should add a non-clustered index just on cntnr_id in this table.

Is there a recommended practice for this scenario? Should I always add certain indexes with relationships like this?

A lot of the queries are either joining these two tables together on cntnr_id or doing a select on cntnr_content by specifying the cntnr_id. This is also an update/delete heavy table. Updates and deletes are always done on the primary key (cntnr_content_id).

Best Answer

Clustered indexes are stored physically on disk as a binary tree. Typically they are great for read heavy workloads.

The reason the profiler is suggesting that you not use a non-clustered index on the cntnr_content table is because you typically will access data on that table using the foreign key.

In this situation, the clustered index on your primary key is not useful as the data is spread across the disk in a way that is hard to find when using the foreign key. That's why it suggests using non-clustered indexes.

Changing to non-clustered indexes allows the database to choose an on disk format that is more optimal for lookups via the foreign key. Of course, doing so will affect the speed of lookups on the primary key, so it's a trade off - you get more speed in one case, but sacrifice some speed in another case.