繁体   English   中英

MySQL 查询非常慢 - 偶尔

[英]MySQL queries very slow - occasionally

我在 Ubuntu 18.4.4 LTS 上运行 MariaDB 10.2.31。 我经常遇到以下难题 - 特别是在早上开始时,即我的 DEV 环境在夜间闲置时 - 而且在白天有时也会遇到。

我有一张桌子(这也适用于其他桌子),大约。 15.000 行和(除其他外)VARCHAR 列上的索引,平均包含 5 到 10 个字符。 值得注意的是,包括这一列在内的大多数列都是生成的GENERATED ALWAYS AS (JSON_EXTRACT(....)) STORED ,因为我的 99% 的数据来自 REST API 作为 JSON 编码的字符串(方便我将它们存储在一列中并提取所有内容别的)。

在该列上运行查询时WHERE colname LIKE 'text%'我发现查询结果持续时间为 0.006 秒。 好的。 当我有我的查询EXPLAIN编辑时,我可以看到索引正在被使用。 然而,正如我所提到的,当我早上开始时,这需要更长的时间(今天早上 14 秒)。 我知道查询缓存,我在关闭查询缓存的情况下尝试了这个(通过SET GLOBAL query_cache_type=OFFRESET QUERY CACHE )。 在这种情况下,我得到大约一致的时间。 0.3 秒 - 正如预期的那样。

那么,你建议我应该研究什么? 我的数据库在睡觉吗? 有这样的事吗?

有两件事可能会发生:

1) 冷缓存(隔夜备份、mysqld 重启或大型处理作业会导致此特定索引和表数据从内存中逐出)。

2) 表 go 的统计数据陈旧,查询计划器会感到困惑,直到您对表运行一些查询并刷新统计数据。 您可以使用 ANALYZE TABLE table_name 强制更新。

3)查询规划器heisenbug。 在 MySQL 5.7 及更高版本中非常常见,以前从未在 MariaDB 上见过它,所以这不太可能。

您可以通过在配置中启用以下内容来深入了解:

log_output='FILE'
log_slow_queries=1
log_slow_verbosity='query_plan,explain'
long_query_time=1

然后在您看到缓慢发生后查看缓慢日志中的内容。 如果记录的解释计划在慢速和快速情况下看起来都一样,那么你有一个冷缓存问题。 如果它们不同,则您有一个表统计信息问题,您需要在通宵任务结束时 cron ANALYZE TABLE读取/写入该表很多。 如果这没有帮助,作为最后的手段,使用FORCE INDEX (index_name)将索引提示硬编码到您的查询中。

使用log_slow_verbosity=query_plan,explain和足以捕获结果的long_query_time启用慢查询日志 看看它是否偶尔使用不同的(或没有)索引。

在开始第二天之前,请查看SHOW GLOBAL STATUS LIKE "innodb_buffer_pool%"并在查询后再次查看值。 查看有多少缓冲池读取与读取请求处于此状态 output 以查看是否所有都从磁盘中脱落。

正如@Solarflare 所提到的,备份和夜间活动可能会清除缓存数据的 innodb 缓冲池并将坏数据恢复到磁盘以使其再次变慢。 作为夜间活动的一部分,您可以设置innodb_buffer_pool_dump_now=1以在脚本活动之前保存热页面,并设置 innodb_buffer_pool_load_now=1以恢复它。

大喊并感谢大家提供宝贵的见解:从你们提供的所有提示中,我想我开始更好地理解问题并开始缩小范围:

我发现的第一件事是我的默认innodb_buffer_pool_size为 134 MB。 对于我正在处理的数据的种类和数量,这非常低 - 所以我能够增加它。 Very helpful post: https://dba.stackexchange.com/a/27341 And from the docs: https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool-resize.html

现在我已经将它增加到接近 2GB 并且能够监控它的使用情况和一般的 RAM 使用情况(cli:cat /proc/meminfo)我意识到我的 4GB RAM 实际上处于低端。 我几乎看不到任何未使用的开销(缓冲区使用率仍为 99%,可用 RAM 约为 100MB)。

接下来我将开始优化我的守护进程的 RAM 使用情况,看看这会导致什么——但这不会完全释放足够的 RAM。

@danblack 提到innodb_buffer_pool_dump_nowinnodb_buffer_pool_load_now 这是一种有趣的方法,可以在守护程序访问数据库时使用,因为我希望将守护程序的缓冲区使用与前端的(显然这是不可能的)分开。 我会进一步研究,但由于我的守护进程一直在运行(不仅在晚上),这可能不可行。

@Gordan Bobic 通过使用ANALYZE TABLE tableName提到了“刷新” DBtables。 我发现这非常快,并在每次进行广泛的读/写后将其合并到守护程序中。 这会将守护程序的运行时间增加几秒钟,但这根本不是问题。 而且我认为我不能 go 错了:)

所以,最后我相信我的问题是多种因素的结合:缓冲区太小,RAM 太小,该环境的读/写操作太多(驱逐缓冲索引等)。 此外,我将不得不了解更多关于 memory 分配等的信息,并更好地优化这一点(大页面 = 1 等)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM