【问题标题】:MySql execution path suddenly varies a lot, is inconsistent and slowMySql执行路径突然变化很大,不一致且慢
【发布时间】:2018-02-07 23:21:39
【问题描述】:

我在 MySQL 上的执行路径有问题,导致查询缓慢且不一致。这是一个全新的现象。我们有其他表具有相同的设置(好吧,尽可能接近),这很好,但由于某种原因,现在创建新表存在这个缓慢/不一致的问题。

我们正在使用版本: 带有 InnoDB 的“mysql Ver 14.14 Distrib 5.6.31,用于 debian-linux-gnu”。数据库位于一个 vagrant box 中。

该行为在另一台计算机上重现,并且是在全新版本的 vagrant box 之后。

正如我所说,数据库在我本地机器上的一个 vagrant box 中,我的机器没有承受重负载。

t1 有大约 1m 行。 t2 是一个新表。

这是始终重现问题的最简单查询:

SELECT
    *
FROM
    redacted_t1 AS t1
        JOIN
    redacted_t2 AS t2 ON t1.a_column = t2.id
WHERE
t2.c_column != 'asdff'
ORDER BY t1.b_column DESC;

请参阅下面一些较慢(超过 3 秒)的执行路径示例

我已经看到至少 2 个其他执行路径(也很慢),但由于难以重现(随机?)我无法在此处发布它们。

有时,但不经常,我不知道如何或为什么会发生以下执行路径:

这非常快,0.00 秒。有时拥有数据库的全新版本(如在新的 vagrant box 中),并在 t1 和 t2 上运行优化会产生此结果。有时优化 什么也没做。有时这种执行状态是在没有优化表的情况下实现的。请注意,与慢速执行路径相比,t1 的“行”计数要低得多。 这与我在运行“SHOW STATUS;”时看到的一致。

CREATE TABLE `redacted_t2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,

  -- redacted

  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci

CREATE TABLE `redacted_t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a_column` int(11) DEFAULT NULL,

  -- redacted

  PRIMARY KEY (`id`),

  -- redacted

  KEY `redacted_t1_a_column` (`a_column`),

  -- redacted

  CONSTRAINT `fk_redacted_t1_2032420404` FOREIGN KEY (`a_column`) REFERENCES `redacted_t2` (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=redacted DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci

所以我有几个问题:

1) 为什么执行路径如此不一致,为什么我们以前从未遇到过这种情况?

2) 我们如何解决这个问题,所以应该花费 0.00 秒的查询不会随机花费 3 秒?

【问题讨论】:

  • 您的屏幕截图显示的查询与您问题中的文字不同。 b_column (t2.b_column != 'asdff') 上的屏幕截图过滤器,c_column (t2.c_column != 'asdff') 上的文本过滤器。哪个是正确的?
  • 好收获。它是哪一列并不重要,只要它来自 t2 表即可。
  • 我问的原因是确保在过滤器中实际使用的列上有一个索引。由于您的问题中显示的 DDL 不包括 b_columnc_column,因此我无法判断查询是否过滤了索引列。

标签: mysql sql database performance explain


【解决方案1】:

解决了。

显然,优化器...不是那么好。如果优化器无法处理您的查询,请将查询稍微复杂一些。

所以我在 ORDER BY 中添加了一列。这解决了一切。不理想,但由于某种原因它可以工作。

SELECT
    *
FROM
    redacted_t1 AS t1
        JOIN
    redacted_t2 AS t2 ON t1.a_column = t2.id
WHERE
t2.c_column != 'asdff'
ORDER BY t1.b_column, t2.id DESC;

【讨论】:

    【解决方案2】:

    您可以尝试运行EXPLAIN EXTENDED,然后运行SHOW WARNINGS,以获取有关查询执行计划的更多详细信息。详情请见8.8.3 Extended EXPLAIN Output Format

    您还可以尝试在 t1t2 上运行 ANALYZE TABLE,以确保 MySQL 在选择其执行计划时使用更新的表统计信息。

    redacted_t2.c_column 上添加索引可能会有所帮助,因为您正在过滤该列。

    EXPLAIN 输出来看,MySQL 有时似乎不使用索引redacted_t1_a_column。您可以鼓励或强制数据库使用带有index hints 的索引,例如USE INDEXFORCE INDEX

    【讨论】:

    • 显示警告没有任何问题,只是代码 1003(我理解是使用 EXPLAIN EXTENDED 的代码)。 ANALYZE TABLE 在您执行 OPTIMIZE TABLE 时运行,我尝试过,请参阅我的原始问题 =) 不幸的是,向 redacted_t2.c_column 添加索引没有帮助。
    • SHOW WARNINGS 结果的Message 列是否包含任何有趣的内容?
    • 它没有。只是您的标准内容,在选择、连接、位置和排序依据中带有转义和重命名的列。我会发布它,但我无权这样做。但它对我来说看起来不错。
    【解决方案3】:
    SET innodb_stats_sample_pages = 30;
    ANALYZE TABLE t1;
    ANALYZE TABLE t2;
    

    然后看看是否更一致。由于您正在运行 >5.6.6,因此统计信息应该是“持久的”。不要使用OPTIMIZE TABLE

    继续优化:

    您真的需要两个表中的所有列 (SELECT *) 吗?它在优化和索引方面有所不同。您是否向我们展示了所有相关索引?是否有 TEXTBLOB 列?您需要获取它们吗?

    t2.c_column != 'asdff' 占表格的百分之几?如果是很小的百分比,那么您需要INDEX(c_column)

    t2 是否只有 5 行长?如果是这样,索引、解释计划等就无关紧要了。

    【讨论】:

    • 如果 t2 的行只有 5 行,请解释解释计划和索引如何无关紧要?那么我应该如何/在哪里寻找问题? t2 是一个新表,所以它是空的,有时我加起来最多 300 行,行为是一样的。
    • EXPLAIN 可能会也可能不会改变。从 5 行中查找特定行:使用索引会产生一些使用索引的开销;不使用索引会有一些跳过其他 4 行的开销。时间差可能是亚毫秒。 (而且我无法预测哪个会更快。)对于 300 行,索引变体可能会更快。故事的寓意:从小表推断性能是危险的。
    猜你喜欢
    • 2011-04-25
    • 2015-01-22
    • 2018-08-19
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多