I've created a table with a nonclustered PK (this is by design), and an additional nonclustered index on the column I'm filtering with a WHERE
clause ([target_user_id]
):
CREATE TABLE [dbo].[MP_Notification_Audit] (
[id] BIGINT IDENTITY (1, 1) NOT NULL,
[type] INT NOT NULL,
[source_user_id] BIGINT NOT NULL,
[target_user_id] BIGINT NOT NULL,
[discussion_id] BIGINT NULL,
[discussion_comment_id] BIGINT NULL,
[discussion_media_id] BIGINT NULL,
[patient_id] BIGINT NULL,
[task_id] BIGINT NULL,
[date_created] DATETIMEOFFSET (7) CONSTRAINT [DF_MP_Notification_Audit_date_created] DEFAULT (sysdatetimeoffset()) NOT NULL,
[clicked] BIT NULL,
[date_clicked] DATETIMEOFFSET (7) NULL,
[title] NVARCHAR (MAX) NULL,
[body] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_MP_Notification_Audit1] PRIMARY KEY NONCLUSTERED ([id] ASC)
);
[...]
CREATE NONCLUSTERED INDEX [IX_MP_Notification_Audit_TargetUser] ON [dbo].[MP_Notification_Audit]
(
[target_user_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
This table has about 11,700 rows of data in, so it should be enough to trigger the use of indexes with WHERE
clauses. If I SELECT
just the column I'm filtering on, only the index is used and 133 matching rows are read - an index-only scan:
SELECT [target_user_id]
FROM [TestDb].[dbo].[MP_Notification_Audit]
WHERE [target_user_id] = 100017
However, as soon as I add an extra column to the SELECT
, the index is ignored and a table scan with a predicate is done to attain the result, reading over 11,700 rows:
SELECT [target_user_id], [patient_id]
FROM [TestDb].[dbo].[MP_Notification_Audit]
WHERE [target_user_id] = 100017
Why is it ignoring my index in this second query? I'd have thought it would still be more efficient to use the index to get down to 133 RIDs, then query the extra row data required, than to go through every row of the table with a predicate? I know I can add columns to the index with INCLUDE
with the extra fields needed in the SELECT
clause to make it use the index again, but I'm interested as to why it doesn't still use the index in this case.