【问题标题】:SQL Server - index scan where index seek expectedSQL Server - 预期索引搜索的索引扫描
【发布时间】:2014-10-07 00:21:14
【问题描述】:

我正在尝试删除索引扫描,但以我目前的理解,我似乎无法弄清楚如何使其成为搜索。我查看了整个 SO 中的其他帖子,这些帖子表明索引中列的顺序需要正确,并且据我目前的理解,它们似乎是正确的,但我可能完全不正确。也许订单根本不是答案。

这里是查询:

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

我认为值得一提的是,Activity.ActionObjectId 不是对 UserDocument.UserDocumentId 的外键引用——它是一个松散的列,我们用来存储其他主键值,然后我们根据 Activity 有条件地链接到这些值。行动。

当前 PK/指数:

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

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

DocumentTypeId 是 int 不为空。

查询计划最终产生:

  • 哈希匹配(聚合)12%
  • 哈希匹配(内连接)57%
  • 索引扫描(非集群)[UserDocument].[ix_ud_dtid] 28%

内部连接哈希匹配也溢出到 tempdb 中。不确定这是否有用。

将鼠标悬停在索引扫描上时,实际记录数为 468,392。

有什么想法吗?我会显示图像,但我没有代表。我很乐意以任何方式提供所需的更多信息。

编辑 1:

表结构如下:

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
)

dbo.Activity 表上的索引:

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]
)

【问题讨论】:

  • 很难说没有表结构和计划的更多细节。一个猜测是,在 ix_ud_dtid 索引中找到行后的 pk 查找成本被认为高于索引扫描。话虽如此,这个问题可能会在 dba.stackexchange 上找到更好的受众。
  • Activity 表上有索引吗?它们同样重要。
  • @TheVedge - 我添加了表格结构,看看它是否有助于绘制更清晰的画面。我在 SO 上看到了一些非常好的答案,但如果我在这里没有任何运气,我也会去 DBA。
  • @RogerF.Wolf - 我已经编辑了帖子以包含活动表中的索引。
  • @Mark 看看这个,它可能是多种因素的组合。我会说 ix_ud_dtid 用于在分组上节省一些周期。就行数而言,Activity 表是否比 UserDocument 大得多?此外,从它的外观上看,索引 Activity.ActivityObjectId 会给您带来更大的收益

标签: sql sql-server indexing


【解决方案1】:

我宁愿从dbo.Activity 表上的索引开始。现有的都不适合这个查询,但其中一个应该是诀窍:

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

dbo.UserDocument 表上的索引很好。

哦,是的,在排序时将datetime 列转换为date 是没有意义的。它不会给你任何有用的东西,但肯定会破坏你可能拥有的索引的任何好处。

【讨论】:

  • 感谢您的回复。我希望 dbo.UserDocument 上的索引很好——它们似乎还可以。我没有意识到 dbo.Activity 上的索引不正确会导致对 dbo.UserDocument 进行扫描。我确实尝试了答案中提供的第二个和第三个索引,但我没有运气; dbo.UserDocument 上仍有扫描。我还更新了这些表的统计信息,以防万一。我将 datetime 转换为 date 以删除时间因素,因此分组仅适用于日期而不考虑时间。有没有更好的方法来做到这一点?
  • @Mark,哎呀,我没有注意到它是分组,而不是排序。转换为不同的数据类型通常会导致忽略此类字段上的所有索引。尝试删除cast(),只是为了检查计划是否会理顺。此外,您可能会发现索引表变量很有用:DECLARE @ChartActions TABLE (InValue int primary key);
  • 我怀疑投射它可​​能会导致它忽略索引,所以我也尝试删除投射。似乎仍然没有运气。它仍然尝试使用 ix_ud_dtid 对 UserDocument 进行索引扫描。我还在@ChartActions 中将 InValue 设为 PK。 (它也会对其进行聚集索引扫描,但我怀疑这只是少量的行。)
  • @Mark,检查关于这两个表的 SQL Server 索引建议。我怀疑您可能过于简化了您的查询。另外,dbo.UserDocument 表实际上受到了多少影响?如果是10-20%%左右或者更多,索引扫描其实是更好的策略。
  • 是的,我开始认为可能只是 SQL Server 决定执行扫描更快。否则,我就没主意了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 2012-01-31
相关资源
最近更新 更多