【问题标题】:Delete all entries over 15 minutes old删除所有超过 15 分钟的条目
【发布时间】:2011-07-10 12:51:09
【问题描述】:

我有一张桌子,每分钟大约有 10-15k 个条目。每一个都标有进入时的当前时间戳。该表是MEMORY 表,因为丢失数据不是问题。

每分钟,我都有一个运行以下查询的脚本:

DELETE FROM tracker WHERE post_time < DATE_SUB(NOW(), INTERVAL 15 MINUTE)

这个查询运行大约需要 1-2 秒,这还不错,但似乎这种类型的查询(删除所有早于X 的内容)在针对MEMORY 表。它还对 CPU 有一个相应的尖峰,每分钟都像拇指酸痛一样伸出来。

我可以对我的查询进行任何优化以更有效地运行此查询吗?

【问题讨论】:

  • 时间戳列有索引吗?
  • 最终你可以用 PHP 计算时间?

标签: mysql performance


【解决方案1】:

与往常一样,您应该查看查询计划并将其发布在此处。你可以通过发出EXPLAIN DELETE FROM tracker WHERE post_time &lt; DATE_SUB(NOW(), INTERVAL 15 MINUTE) 来做到这一点

现在,问题很可能是 DELETE 查询不能使用索引,并且必须遍历所有行。

即使你已经在 post_time 上有一个索引,它也可能不会被使用,因为 MEMORY 表上的默认索引是哈希索引。 哈希索引只能用于相等性检查,不能用于post_time &lt; DATE_SUB(NOW(), INTERVAL 15 MINUTE)等范围

在您的 post_time 列上创建 BTREE 索引,

CREATE INDEX post_time_idx ON tracker (post_time) USING BTREE;

【讨论】:

  • 非常感谢。将索引从 HASH(默认)更改为 BTREE 完全消除了该问题。 CPU 使用图现在几乎没有注册查询。
【解决方案2】:

在 post_time 上建立索引。如果匹配 post_time &lt; DATE_SUB(NOW(), INTERVAL 15 MINUTE) 的行是整个表的一小部分,这应该会加快速度。

【讨论】:

    【解决方案3】:

    如果您的表中的数据从不超过 15 分钟,您可以使用比 DATETIME 更小的数据类型来存储您的时间戳。根据您关心的粒度,您可能会使用 非常 小数据类型...使用 SMALLINT 您可以存储“自午夜以来的分钟数”。如果您愿意失去更多的粒度,您可以使用 TINYINT 来获得 15 分钟的粒度。当然,这需要稍微复杂一点的逻辑,来处理“午夜过后”的案件......

    DELETE FROM tracker
    WHERE (
        EXTRACT(DAY_MINUTE FROM NOW()) > 15
        AND post_time < EXTRACT(DAY_MINUTE FROM NOW())
    ) OR (
        post_time < EXTRACT(DAY_MINUTE FROM NOW()) < 15
        AND post_time < EXTRACT(DAY_MINUTE FROM NOW()+60)
    )
    

    优点是你必须读取和比较的数据要小得多,因此可以更快地处理。如果您将数据存储在磁盘 I/O 比内存带宽更重要的磁盘上,这将产生更大的影响。

    此外,对于只有 10-15k 行和适当索引的表,我怀疑这会产生任何明显的差异——无论是在磁盘上还是在内存中。

    【讨论】:

    • 我怀疑这会对性能产生任何的积极影响。大多数现代计算机都经过优化,可以使用至少 32 位的值,使用 8 位的值就像有一个 10 英寸的管道,而只有 2.5 英寸的水流过它。尝试打包较小的值来填充带宽通常会对性能产生负面影响。
    • @Autumn:这种方法被证明可以在许多情况下提高性能——我在回答中概述了这一点。它最显着地有助于磁盘 I/O——这与 CPU 的位数完全无关。在某些情况下,它还可以大大提高索引的性能,索引较少的值有助于提高性能。
    • @Autumn:我还应该指出,数据库对这些整数执行的操作类型很少与整数数学有关,因此您的整个前提是 CPU 针对 32 位整数进行了优化,因此 32 位整数会表现得更好,这是完全没有根据的。
    • @Autumn:哦,还有一点…… DATETIME 也不是 32 位数据类型。因此,即使您的观点总体上是有效的(实际上不是),在这种特定情况下它仍然是完全无效的。
    猜你喜欢
    • 2016-09-19
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多