【问题标题】:SQL Server - Query performs Index Scan instead of SeekSQL Server - 查询执行索引扫描而不是查找
【发布时间】:2012-06-28 14:35:42
【问题描述】:

我正在使用 Lucene 为 CMS 的内容建立索引,因此我扩展了 SQL Server 数据库架构以添加“IsIndexed”位列,因此 Lucene 索引器可以找到一段没有' t 已被编入索引。

我向Content 表添加了一个索引,因此IsIndexed 列的查找速度应该更快。这是数据库的样子:

CREATE TABLE Content (
    DocumentId bigint,
    CategoryId bigint,
    Title nvarchar(255),
    AuthorUserId bigint,
    Body nvarchar(MAX),
    IsIndexed bit
)
CREATE TABLE Users (
    UserId bigint,
    UserName nvarchar(20)
)

存在以下索引:

Content (
    PK_Content (Clustered) : DocumentId ASC
    IX_CategoryId (Non-Unique, Non-Clustered) : CategoryId ASC
    IX_AuthorUserId (Non-Unique, Non-Clustered) : AuthorUserId ASC
    IX_Indexed_ASC (Non-Unique, Non-Clustered) : IsIndexed ASC, DocumentId ASC
    IX_Indexed_DESC (Non-Unique, Non-Clustered) : IsIndexed DESC, DocumentId ASC
)

Users (
    PK_Users (Clustered) : UserId
)

这是用于查找非索引内容的查询:

SELECT
    TOP 1
    Content.DocumentId,
    Content.CategoryId,
    Content.Title,
    Content.AuthorUserId,
    Content.Body
    Users.UserName
FROM
    Content
    INNER JOIN Users ON Content.AuthorUserId = Users.UserId
WHERE
    IsIndexed = 0

但是,当我运行它时,实际执行计划会报告 PK_Content 的聚集索引扫描以及 PK_Users 的聚集索引搜索。执行查询大约需要 300 毫秒。

当我修改查询以删除 Users.UserName 字段和 Users 内连接时,查询需要大约 60 毫秒才能运行,并且没有针对 PK_Content 的聚集索引扫描,只有针对 PK_Content 的聚集索引搜索。

我在为 Content.IsIndexed 列添加降序索引之前和之后都尝试过这个,我还在 IX_Indexed 索引中添加了Content.DocumentId,但没有任何区别。

我做错了什么?我已经制作了所有必要的索引(然后是一些)。 Content 表有数十万行,Users 表也是如此,所以我不明白为什么优化器会选择扫描。

【问题讨论】:

  • 有什么被索引了吗?如果所有(或大部分)行的 IsIndexed 等于 0,则不太可能使用索引
  • 大约 30% 的所有内容行的 IsIndexed = 1

标签: sql-server indexing


【解决方案1】:

使用IsIndexed 字段和AuthorUserId 字段向内容添加索引,然后它应该进行搜索。根据您的 SQL Server 版本,您可以添加一个 INCLUDE 语句,其中包含您在 select 中使用的字段,以获得更快的速度。

IX_Indexed_AuthorUserId(非唯一,非集群):IsIndexed, 作者用户ID

【讨论】:

  • 谢谢。添加该索引后,实际查询执行计划报告它执行了两次索引搜索并且没有进行索引扫描,但是查询仍然需要大约 300 毫秒才能运行。
【解决方案2】:

如此低选择性列(只有两个值 0 和 1)上的索引总是会被忽略,请参阅 the tipping point。一种选择是将它作为聚集索引中最左边的键移动,并将 DocumentId 上的主键约束设为非聚集索引:

CREATE TABLE Content (
    DocumentId bigint,
    CategoryId bigint,
    Title nvarchar(255),
    AuthorUserId bigint,
    Body nvarchar(MAX),
    IsIndexed bit,
    constraint pk_DocumentId primary key nonclustered (DocumentId)
)

create unique clustered index cdxContent on Content (IsIndexed, DocumentId);

另一种选择是创建过滤覆盖索引:

create unique index nonIndexedContent on Content (DocumentId)
  include (CategoryId, Title, AuthorUserId, Body)
  where IsIndexed = 0;

第二个选项可能会复制很多内容。就个人而言,我会选择第一个选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-16
    • 2018-11-03
    • 2011-08-22
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    相关资源
    最近更新 更多