MySql 执行路径突然变化很大,不一致且缓慢
MySql execution path suddenly varies a lot, is inconsistent and slow
我在 MySQL 的执行路径上遇到问题,导致查询缓慢且不一致。这是一个全新的现象。我们有其他 tables 具有相同的设置(好吧,尽可能接近),这很好,但出于某种原因,创建新的 tables 现在有这个 slow/inconsistent 问题。
我们使用的版本:
"mysql Ver 14.14 Distrib 5.6.31, for debian-linux-gnu" 与 InnoDB。数据库存在于一个 vagrant box 中。
该行为在另一台计算机上重现,并且是在全新版本的 vagrant box 之后。
正如我所说,数据库在我本地机器上的一个 vagrant box 中,我的机器负载不重。
t1 大约有 100 万行。
t2 是一个新的 table.
这是始终重现问题的最简单的查询:
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 个其他执行路径(它们也很慢)但是因为很难重现(随机?)我不能在这里 post 它们。
有时,但不经常,我不知道如何或为什么会发生以下执行路径:
这非常快,0.00 秒。有时拥有一个全新版本的数据库(如在一个新的 vagrant box 中),并且 运行ning 在 t1 和 t2 上进行优化会产生这个结果。有时优化
什么也没做。有时这种执行状态是在没有优化table的情况下实现的。请注意,与慢速执行路径相比,t1 的 'rows' 计数要低得多。
这与我 运行 "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 秒?
您可以尝试 运行 EXPLAIN EXTENDED
,然后 SHOW WARNINGS
,以获得有关查询执行计划的更多详细信息。有关详细信息,请参阅 8.8.3 Extended EXPLAIN Output Format。
您还可以在 t1
和 t2
上尝试 运行 ANALYZE TABLE 以确保 MySQL 在选择其时使用更新的 table 统计信息执行计划。
在 redacted_t2.c_column
上添加索引可能会有所帮助,因为您正在过滤该列。
从 EXPLAIN
输出来看,似乎 MySQL 有时没有使用索引 redacted_t1_a_column
。您可以鼓励或强制数据库使用带有 index hints 的索引,例如USE INDEX
或 FORCE INDEX
.
SET innodb_stats_sample_pages = 30;
ANALYZE TABLE t1;
ANALYZE TABLE t2;
然后看看是不是比较一致。由于您 运行 >5.6.6,统计数据应该是 'persistent'。不要使用 OPTIMIZE TABLE
.
继续优化:
您真的需要两个 table (SELECT *
) 中的所有列吗?它在优化和索引方面有所不同。您是否向我们展示了所有相关指标?是否有 TEXT
或 BLOB
列?您需要取回它们吗?
table 的百分比是 t2.c_column != 'asdff'
?如果它是一个小百分比,那么你需要 INDEX(c_column)
.
t2
只有5行吗?如果是这样,索引、解释计划等将无关紧要。
已解决。
显然,优化器...不是很好。如果优化器无法处理您的查询,请使查询稍微复杂一些。
所以我在 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;
我在 MySQL 的执行路径上遇到问题,导致查询缓慢且不一致。这是一个全新的现象。我们有其他 tables 具有相同的设置(好吧,尽可能接近),这很好,但出于某种原因,创建新的 tables 现在有这个 slow/inconsistent 问题。
我们使用的版本: "mysql Ver 14.14 Distrib 5.6.31, for debian-linux-gnu" 与 InnoDB。数据库存在于一个 vagrant box 中。
该行为在另一台计算机上重现,并且是在全新版本的 vagrant box 之后。
正如我所说,数据库在我本地机器上的一个 vagrant box 中,我的机器负载不重。
t1 大约有 100 万行。 t2 是一个新的 table.
这是始终重现问题的最简单的查询:
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 个其他执行路径(它们也很慢)但是因为很难重现(随机?)我不能在这里 post 它们。
有时,但不经常,我不知道如何或为什么会发生以下执行路径:
这非常快,0.00 秒。有时拥有一个全新版本的数据库(如在一个新的 vagrant box 中),并且 运行ning 在 t1 和 t2 上进行优化会产生这个结果。有时优化 什么也没做。有时这种执行状态是在没有优化table的情况下实现的。请注意,与慢速执行路径相比,t1 的 'rows' 计数要低得多。 这与我 运行 "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 秒?
您可以尝试 运行 EXPLAIN EXTENDED
,然后 SHOW WARNINGS
,以获得有关查询执行计划的更多详细信息。有关详细信息,请参阅 8.8.3 Extended EXPLAIN Output Format。
您还可以在 t1
和 t2
上尝试 运行 ANALYZE TABLE 以确保 MySQL 在选择其时使用更新的 table 统计信息执行计划。
在 redacted_t2.c_column
上添加索引可能会有所帮助,因为您正在过滤该列。
从 EXPLAIN
输出来看,似乎 MySQL 有时没有使用索引 redacted_t1_a_column
。您可以鼓励或强制数据库使用带有 index hints 的索引,例如USE INDEX
或 FORCE INDEX
.
SET innodb_stats_sample_pages = 30;
ANALYZE TABLE t1;
ANALYZE TABLE t2;
然后看看是不是比较一致。由于您 运行 >5.6.6,统计数据应该是 'persistent'。不要使用 OPTIMIZE TABLE
.
继续优化:
您真的需要两个 table (SELECT *
) 中的所有列吗?它在优化和索引方面有所不同。您是否向我们展示了所有相关指标?是否有 TEXT
或 BLOB
列?您需要取回它们吗?
table 的百分比是 t2.c_column != 'asdff'
?如果它是一个小百分比,那么你需要 INDEX(c_column)
.
t2
只有5行吗?如果是这样,索引、解释计划等将无关紧要。
已解决。
显然,优化器...不是很好。如果优化器无法处理您的查询,请使查询稍微复杂一些。
所以我在 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;