【问题标题】:Low cardinality index with uneven distribution of possible values可能值分布不均匀的低基数指数
【发布时间】:2020-04-18 10:20:52
【问题描述】:

我有一个table that's used as a queue

create table items 
(
    itemId     int, -- PK, identity
    status     int, -- Possible values: 0 = Pending, 1 = Processing, 2 = Processed
    createdAt  datetime2,
    updatedAt  datetime2,
    content    text
)

生产者将记录添加到队列中,消费者 FIFO 读取它们:

  • 生产者添加状态为Pending 的记录,createdAt 作为当前时间
  • 消费者选择Pending状态下的记录,按createdAt排序。消费时,他们将记录标记为Processing,并将updatedAt 设置为当前时间(使用update/select CTE)
  • 处理后,消费者将记录标记为Processed
  • 在处理过程中,消费者可能会崩溃,因此无法将记录标记为Processed
  • 当另一个消费者发现一条记录停留在Processing 状态超过 x 分钟(即updatedAt < current_time - xstatus = Processing)时,他们会捡起并处理(假设新消费者不会崩溃;))
  • 表有大约 100 万条记录,每天增长大约 20k
  • 在任何给定时间都会有 Pending 和 Processing 记录

我有 2 个问题

  1. 考虑到这种情况(尤其是最后 2 点),(status, createdAt) 上的索引是否包含 updatedAt 作为包含列?

我试过了,它表明索引被命中并且执行时间非常快(亚秒级)。但是,我不太确定这个低基数索引(起始列status)是一个好的索引,因为这样的索引是generally considered bad。我想知道它是否适用于我的情况,因为可能值的分布非常不均匀(Pending,InProgress,这是我要查询的。没有运行查询来选择 @ 987654343@ 个)。

  1. 我添加了包含的列 (updatedAt) 以支持此过滤器 status = Processing and updatedAt < current_time - x,但我不确定它是否有用。查询规划器关心包含的列还是只查看索引中的列 (status, createdAt)?

如果您回答两个问题,则可获得奖励积分;)

【问题讨论】:

    标签: sql sql-server performance sql-tuning query-tuning


    【解决方案1】:

    索引的主要目的之一是减少从表中读取的行数。低基数索引意味着一列只接受少数几个值。因此,如果一个表有一千万行并且有十个值,那么每个值平均会有一百万行。

    索引对于从一千万行表中获取一百万行没有帮助,因为每个(或几乎每个)数据页都会有一个匹配的行。目的是减少正在读取的数据页数。

    因此,您对索引的使用是非常合理的,因为您只找到了几行。您正在使用索引来查找未处理的行,而且这些行很少。

    您的索引比必要的大得多,因为它包含有关已处理行的信息。您可能会考虑过滤索引。根据您的描述,我认为应该是:

    create index idx_items_status_updated
        on items(status, updated)
        where status in (1, 2);
    

    有时,在这些情况下,您希望在state 上使用聚集索引。基本上,这允许将“已处理”项目组合在一起。而且,如果它们所在的数据页未被访问,则不需要加载这些数据页。

    不过,在您的情况下,我猜测项目是按顺序添加的,因此只会处理最近的项目。较旧的数据页将填充已处理的项目,并且——因为它们从未被引用——甚至可能不会占用内存空间。

    【讨论】:

    • 谢谢@Gordon 你能否就第二部分给出一些提示,即包含的列是否有必要?
    • @ubi 。 . .包含列会减少索引的大小,因此这对于优化很重要。但在实践中,我通常只是将附加列添加为键。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-01
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 2020-01-15
    相关资源
    最近更新 更多