【问题标题】:Poor query with table scans occasionally takes hours on MariaDB在 MariaDB 上使用表扫描进行不良查询有时需要数小时
【发布时间】:2026-02-14 04:55:02
【问题描述】:

我的应用程序使用 MariaDB 数据库,我试图保持隔离,但一位特定用户直接访问该数据库并在 6 周后今天开始抱怨他们的一个查询从 5 分钟变慢(我认为这很糟糕)足够)超过120分钟。

从今天开始,它有时像往常一样快,有时又放慢了速度。

这是他们的查询:

SELECT MAX(last_updated) FROM data_points;

这是桌子:

CREATE TABLE data_points (
  seriesId INT UNSIGNED NOT NULL,
  modifiedDate DATE NOT NULL,
  valueDate DATE NOT NULL,
  value DOUBLE NOT NULL,
  created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  last_updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP()
    ON UPDATE CURRENT_TIMESTAMP,
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  CONSTRAINT pk_data PRIMARY KEY (seriesId, modifiedDate, valueDate),
  KEY ix_data_modifieddate (modifiedDate),
  KEY ix_data_id (id),
  CONSTRAINT fk_data_seriesid FOREIGN KEY (seriesId)
  REFERENCES series(id)
) ENGINE=InnoDB
  DEFAULT CHARSET=utf8mb4
  COLLATE=utf8mb4_unicode_ci
  MAX_ROWS=222111000;

这是解释:

id      select_type     table       type    possible_keys   key     key_len ref     rows    Extra
1       SIMPLE          data_points ALL     NULL            NULL    NULL            NULL    224166191

该表大约有 2.5 亿行,并且增长相对较快。

我可以强迫用户做一些更明智的事情,但在短期内,我很想知道为什么在 6 周的平静之后,查询持续时间今天变得疯狂。我会接受第一个可以解释的答案。

【问题讨论】:

  • “我会接受第一个可以解释的答案。” last_updated 列未编入索引
  • 显而易见的答案是它正在执行表扫描,因为last_updated 列上没有索引。我没有解释(我怀疑你会找到一个)为什么一周需要 5 分钟,然后下周需要 120 分钟。之前的速度可能是因为用户频繁执行查询并且结果被索引,或者新的缓慢可能是由于行数突然增加,或者新的行数提示查询优化器使用不同的查询计划效率较低......或其他一些事情。不过很难说。
  • 只需索引该列并完成它.. 现代 MySQL 版本和 InnoDB 引擎版本现在可以通过在线 DDL 执行此操作而无需停机确保检查正确的文档链接..

标签: mysql mariadb


【解决方案1】:

SELECT MAX(last_updated) FROM data_points; 很容易优化:

INDEX(last_updated)

该索引将使MAX 基本上是即时的。并且它会避免冲击磁盘和缓存(见下文)。

有两个因素控制着非索引速度:

  • 表格的大小,“增长相对较快”,以及
  • [这可能就是您想要的。] 运行查询时缓存了多少表。这可以使速度产生 10 倍的差异。您可以部分测试此声明:

重启mysqld;查询时间;再次计时。第一次运行必须经常打磁盘(因为重新启动);第二个可能在 RAM 中找到了所有内容。

另一件可能会影响计时的事情:如果运行其他一些“大”查询并且它将该表的块从缓存中撞出,那么查询将再次变慢。

相关性:表的大小、innodb_buffer_pool_size 的值和 RAM 量。

关于一个不相关的话题...PRIMARY KEY (seriesId, modifiedDate, valueDate) 看起来很奇怪。 PK 必须是唯一的。日期(日期时间等)可能在同一天/秒内有多个条目;所以你能确定唯一性吗?尤其是两个日期?

(更多)

请解释 4 个日期中每个日期的含义。并问自己是否都需要它们。 (大约一半的表格是这些日期!)

该表有一个AUTO_INCREMENT;其他桌子需要吗?如果不是,则或者可以将其删除,可以用来确保 PK 是唯一的。

为了更好地帮助您,我们需要查看更多查询。

【讨论】:

  • 这正是我所追求的——现在非常有意义。主键可能是次优的。它是一个时间序列数据库,并且该 data_points 表也被反规范化。不是我的决定。真的valueDate 是问题所在。目前,一些查询(不是我的)查询 valueDate 字段时,我认为出于性能考虑,它们应该只获取所有 valueDate 并将其过滤到下游。
  • 顺便说一句,你能推荐一本好的 MariaDB DBA 指南、书籍或课程吗?
  • @Adam - Re DBA 指南:搜索 MySQL 书籍。他们所说的 95% 将适用于 MariaDB;而且还有更多。
  • @Adam - 我在答案中添加了更多内容。