我遇到了MySQL上的执行路径问题,导致查询缓慢且不一致。这是一个全新的现象。我们有其他表格具有相同的精确(好,尽可能接近)设置,这很好,但由于某种原因,创建新表现在有这个缓慢/不一致的问题。
我们正在使用版本: " mysql Ver 14.14 Distrib 5.6.31,for debian-linux-gnu"与InnoDB。数据库位于一个流浪盒中。
该行为在另一台计算机上以及流行盒的全新版本之后再现。
正如我所说,数据库位于我本地机器上的一个流浪盒中,我的机器没有负载很重。
t1有大约1米的行。 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秒。有时在数据库中使用全新版本(如在新的流行框中),并在t1和t2上运行optimize会产生此结果。有时优化 什么也没做。有时在没有优化表的情况下实现此执行状态。请注意,'行的数量要低得多。对于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秒?
答案 0 :(得分:1)
您可以尝试运行EXPLAIN EXTENDED
,然后运行SHOW WARNINGS
,以获取有关查询执行计划的更多详细信息。有关详细信息,请参阅8.8.3 Extended EXPLAIN Output Format。
您还可以尝试在t1
和t2
上运行ANALYZE TABLE,以确保MySQL在选择执行计划时使用更新的表统计信息。
在redacted_t2.c_column
上添加索引可能有所帮助,因为您要对该列进行过滤。
从EXPLAIN
输出,似乎MySQL有时不使用索引redacted_t1_a_column
。您可以鼓励或强制数据库使用index hints索引,例如USE INDEX
或FORCE INDEX
。
答案 1 :(得分:0)
SET innodb_stats_sample_pages = 30;
ANALYZE TABLE t1;
ANALYZE TABLE t2;
然后看看它是否更加一致。由于您运行的是> 5.6.6,因此统计信息应该是“持久的”#。请勿使用OPTIMIZE TABLE
。
继续,优化:
您真的需要两个表中的所有列(SELECT *
)吗?它在优化和索引方面有所不同。你有没有向我们展示所有相关指标?是否有TEXT
或BLOB
列?你需要取它们吗?
该表的百分之t2.c_column != 'asdff'
是多少?如果它是一个小百分比,那么您需要INDEX(c_column)
。
t2
只有5行吗?如果是这样,索引,解释计划等,将无关紧要。
答案 2 :(得分:0)
解决。
显然,优化器......并不是那么好。如果优化器无法处理您的查询,请使查询稍微复杂一些。
所以我在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;