简体   繁体   中英

SQL Server - index scan where index seek expected

I'm attempting to remove an index scan, but I can't seem to figure out how to make it a seek with my current understanding. I've looked at other posts throughout SO that suggest the ordering of the columns in the index need to be correct, and to my current understanding, they seem to be correct, but I could be completely off. And maybe the order isn't the answer at all.

Here is the query:

DECLARE @ChartActions TABLE
(
    InValue INTEGER
);
INSERT INTO @ChartActions
VALUES
(73),
(74),
(75);

with cteGroupedChartActivity AS (
    SELECT MAX(ActivityId) as ActivityId
    FROM Activity
    JOIN UserDocument  ON Activity.ActionObjectId = UserDocument.UserDocumentId
    WHERE   Action IN (SELECT * FROM @ChartActions)
    GROUP BY UserDocument.DocumentTypeId,CAST(Activity.DateCreated AS DATE)
)
select * from cteGroupedChartActivity

I believe it may be worth mentioning that Activity.ActionObjectId is not a foreign key reference to UserDocument.UserDocumentId--it is a loose column that we use to store other primary key values that we then link to conditionally based on Activity.Action.

Current PK/indices:

CONSTRAINT [pk_UserDocuments] PRIMARY KEY CLUSTERED 
(
    [UserDocumentId] ASC
)

CREATE NONCLUSTERED INDEX [ix_ud_dtid] ON [dbo].[UserDocument]
(
    [DocumentTypeId] ASC
)

DocumentTypeId is int not null.

The query plan ultimately yields:

  • Hash Match (Aggregate) 12% <=
  • Hash Match (Inner Join) 57% <=
  • Index Scan (NonClustered) [UserDocument].[ix_ud_dtid] 28%

The inner join hash match also spills over into tempdb. Not sure if that's useful information or not.

When mousing over the index scan, the actual number of records is 468,392.

Any thoughts? I'd show images but I don't have the rep. I would be happy to provide any more info needed in any way that I can.

Edit 1:

Table structures are as follows:

CREATE TABLE [dbo].[Activity]
(
    [ActivityId] [int] IDENTITY(1,1) NOT NULL,
    [UID] [int] NULL,
    [Action] [int] NOT NULL,
    [ActionObjectId] [int] NOT NULL,
    [DateCreated] [datetime] NOT NULL,
    [PID] [int] NULL,
    [Data] [varchar](1024) NULL
)

CREATE TABLE [dbo].[UserDocument]
(
    [UserDocumentId] [int] IDENTITY(1,1) NOT NULL,
    [DocumentTypeId] [int] NOT NULL
)

Indices on dbo.Activity table:

CONSTRAINT [pk_Activity] PRIMARY KEY CLUSTERED 
(
    [ActivityId] ASC
)

CREATE NONCLUSTERED INDEX [ix_a_a__inc__aoid_dc_pid] ON [dbo].[Activity]
(
    [Action] ASC
)
INCLUDE
(
    [ActionObjectId],
    [DateCreated],
    [PID]
)

CREATE NONCLUSTERED INDEX [ix_a_pid_uid_a_aoid_dc_d] ON [dbo].[Activity]
(
    [PID] ASC
)
INCLUDE
(
    [UID],
    [Action],
    [ActionObjectId],
    [DateCreated],
    [Data]
)

I would rather start with indices on dbo.Activity table. None of the existing ones is suitable for this query, but one of these should to the trick:

(Action, ActionObjectId)
(Action, ActionObjectId) include (DateCreated)
(Action, ActionObjectId, DateCreated)

Your indices on dbo.UserDocument table are just fine.

Oh, yes, and there is no sense in casting datetime column into date while sorting. It will not give you anything useful, but will definitely ruin any benefit from an index you may possibly have.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM