在时间戳上创建索引以优化查询

Dan*_*bbs 53 mysql indexing optimization timestamp

我查询了以下表格:

SELECT * FROM MyTable WHERE Timestamp > [SomeTime] AND Timestamp < [SomeOtherTime]
Run Code Online (Sandbox Code Playgroud)

我想优化这个查询,我正在考虑在时间戳上放一个索引,但我不确定这是否有帮助.理想情况下,我想使时间戳成为聚簇索引,但MySQL不支持聚簇索引,主键除外.

  • MyTable 有400万+行.
  • Timestamp实际上是类型INT.
  • 插入一行后,永远不会更改.
  • 任何给定的行数Timestamp平均约为20,但可能高达200.
  • 新插入的行具有Timestamp比大多数现有行更大的行,但可能少于一些较新的行.

索引会Timestamp帮我优化这个查询吗?

Chr*_*ash 52

毫无疑问.如果没有索引,您的查询必须查看表中的每一行.使用索引,只要找到正确的行,查询就会非常即时.您支付的价格是插件的性能略有下降; 但那真的很轻微.

  • 因此,独特时间戳的数量非常高并且因此会产生相当大的索引这一事实没有任何缺点吗? (9认同)
  • 谢谢@ypercube - 只是在答案中限定了这一点:) - 我会说几兆字节的索引的缺点是值得的。数据库擅长这种事情! (2认同)
  • 它将读取20-200行的索引; 这些将在BTree中连续进行.然后它将在表中为所需的任何其他列(`SELECT*`)执行20-200次查找._Very_效率与没有`INDEX(Timetamp)`相比. (2认同)

Rya*_*n P 7

你绝对应该使用索引.MySQL不知道这些时间戳是什么顺序,并且为了找到给定时间戳(或时间戳范围)的记录,它需要查看每个记录.有400万,这是相当多的时间!索引是告诉MySQL关于数据的方式 - "我会经常查看这个字段,所以请列出我可以找到每个值的记录的位置."

对于定期查询的字段,索引通常是一个好主意.定义索引的唯一缺点是它们使用额外的存储空间,所以除非你真的很紧张,否则你应该尝试使用它们.如果它们不适用,MySQL无论如何都会忽略它们.


bla*_*ype 7

我不反对索引对提高选择查询时间的重要性,但如果您可以对其他键进行索引(并使用这些索引形成您的查询),则可能不需要对时间戳进行索引。

例如,如果您有一个包含timestamp,category和的表,userId最好在其上创建索引userId。在具有许多不同用户的表中,这将大大减少用于搜索时间戳的剩余集合。

...如果我没记错的话,这样做的好处是避免在每次插入时创建时间戳索引的开销——在具有高插入率和高度唯一时间戳的表中,这可能是一个重要的考虑因素。

我正在努力解决基于时间戳和其他键的索引问题。我还有测试要做,所以我可以为我在这里所说的内容提供证据。我会尝试根据我的结果回发。

一个更好解释的场景:

  1. 时间戳 99% 唯一
  2. 用户 ID 80% 唯一
  3. 类别 25% 独特

    • 时间戳索引将快速将查询结果减少到表大小的 1%
    • 对 userId 进行索引将很快将查询结果减少到表大小的 20%
    • 分类索引将很快将查询结果减少到表大小的 75%
    • 在时间戳上插入索引将有很高的开销 **
    • 尽管我们知道我们的插入会尊重时间戳递增的事实,但我没有看到任何关于基于增量键的 MySQL 优化的讨论。
    • 使用 userId 上的索引插入将相当高的开销。
    • 在类别上插入索引将具有相当低的开销。

** 对不起,我不知道计算的开销或索引插入。


ype*_*eᵀᴹ 5

如果您的查询主要使用此时间戳,则可以测试此设计(使用时间戳作为第一部分放大主键):

CREATE TABLE perf (
  , ts INT NOT NULL
  , oldPK 
  , ... other columns 
, PRIMARY KEY(ts, oldPK)
, UNIQUE (oldPK)
) ENGINE=InnoDB ;
Run Code Online (Sandbox Code Playgroud)

这将确保您发布的查询之类的查询将使用群集(主)密钥.

缺点是你的插入会慢一点.此外,如果表上有其他索引,它们将使用更多的空间(因为它们将包括4字节更宽的主键).

这种聚簇索引的最大优点是具有大范围扫描的查询,例如必须读取表的大部分或整个表的查询将按顺序和所需顺序(BY timestamp)查找相关行,这也是有用的如果你想按天,周或月或年分组.

旧的PK仍然可以通过对其进行UNIQUE约束来识别行.


您可能还想看看TokuDB,一种允许多个聚簇索引的MySQL(和开源)变体.