![](/img/trans.png)
[英]MySQL: Very slow update/insert/delete queries hanging on “query end” step
[英]Slow Update, Delete and Insert Queries under MariaDB
我们的服务器已从 Ubuntu 16 更新为 Ubuntu 20 和 MariaDB。不幸的是,网站的加载时间变慢了。 通常 MariaDB 应该比 Mysql 快。我发现,很简单,网站上的更新命令有时需要大约 7 秒。 但是,如果我通过 myphpadmin 将这些更新命令直接输入到数据库中,它们只需要 0.0005 毫秒。
在我看来,MariaDB 经常出现更新命令时出现问题。 mysql 从来都不是问题。这是一个查询示例:
UPDATE LOW_PRIORITY users
SET user_video_count = user_video_count + 1
WHERE user_id = 12345
数据库格式为 MyISAM。
我不知道可能是什么原因。 你?
非常感谢你。
它可能像SELECT
在users
中搜索某些内容一样简单。 注意,InnoDB 不会遇到这个问题。
MyISAM
在执行UPDATE
、 INSERT
或DELETE
时必然会锁定表。 (还有ALTER
和其他 DDL 语句。)如果有很多连接在执行写入甚至SELECTs
的任何混合操作,那么锁会级联很长时间。
真正的解决方案,无论是在 MariaDB 还是 [尤其是] 在 MySQL 中,都是切换到 InnoDB。
如果这是对“喜欢”或“观看次数”进行大量计数的情况,则部分解决方案(在任一引擎中)是将此类计数器放在一个单独的并行表中。 这避免了那些简单快速的更新与主表上的其他操作发生冲突。 在人流量极高的区域,收集此类增量并分批应用它们是有必要的。 我认为您的卷不需要那种激进的解决方案。
MySQL 几乎消除了 MyISAM。 MariaDB 可能会在几年后效仿。
为了解决这个问题:
myphpadmin 中的相同查询非常快
问题不在于你如何运行它,而在于同时发生的其他事情。
( LOW PRIORITY
是 MyISAM 特定的 kludge,有时会起作用。)
MyISAM 进行“表锁定”; InnoDB 做“行锁定”。 因此,Innodb 可以在表上执行许多“同时”操作,而 MyISAM 会在写入发生时立即序列化。
更多(现在专注于 InnoDB。)
可能涉及到的其他一些事情。
如果两个UPDATEs
试图同时修改同一行,一个将不得不等待(由于行锁定)。
如果确实有大量事情在发生,延迟可能会一连串地发生。 如果在一个实例中有 20 个连接正在运行,那么它们各自都会减慢彼此的速度。 每个连接都被公平分配,但这意味着它们都变慢了。
SHOW PROCESSLIST
查看正在运行的程序——而不是“睡眠”。 “时间”最长的进程(系统线程除外)很可能是这场争吵的始作俑者。
slowlog 可以帮助更深入地研究。 我打开它,使用足够低的long_query_time
并等待“事件”发生。 然后我使用pt-query-digest
(或mydumpslow -st
)找出最慢的查询。 通过更多的努力,人们可能会注意到有很多查询在某一瞬间“缓慢”——甚至可能是“点查询”(如UPDATE... WHERE id=constant
)意外地比long_query_time
运行得慢。 这表示太多查询和/或某些意外锁定行的查询。 (注意:查询的“时间戳”是查询结束的时间;减去Query_time
即可开始。) SlowLog
更多的
正如您所发现的, innodb_flush_log_at_trx_commit = 2
在快速执行大量单查询事务时是一个很好的修复。 如果该修复的频率变得太大,那么我上面的评论可能就变得必要了。
=2 和 =0 之间不会有太大的性能差异。
至于innodb_flush_log_at_timeout
。 请提供 `SHOW GLOBAL STATUS LIKE 'Binlog%commits'
至于innodb_lock_wait_timeout
...我不认为改变它会对你有帮助。 如果您的查询之一由于该超时而中止,您应该记录它发生并重试事务。
听起来您正在使用autocommit = ON
运行并且不使用显式事务? 这很好(对于非金钱活动)。 在某些情况下,使用事务可以提高性能——例如人为地将多个查询批处理在一起以避免某些 I/O。 缺点是与其他连接发生冲突的可能性增加。 尽管如此,如果您总是检查错误并重新运行“事务”,那么一切都应该很好。
innodb_flush_log_at_trx_commit
当该设置为“1”(可能是您最初的设置)时,每个更新都会额外写入磁盘以确保数据完整性。 如果磁盘是 HDD(而不是 SDD),则每次更新会增加大约 10 毫秒,因此导致每秒大约 100 次更新的最大值。 有几种解决方法。
innodb_flush_log_at_trx_commit = 0 or 2
,牺牲一些数据完整性。我怀疑社交媒体巨头会做上述所有事情。
当您使用 MariaDB 时,您可以使用像 EverSQL 这样的工具来查找丢失的索引或发现冗余索引(例如,您在 user_video_count 上有一个您并不真正需要的索引)
首先我要感谢所有帮助过我的人。 我真的很感激人们尝试投入宝贵的时间。
我想告诉您我是如何设法解决更新、插入和删除查询缓慢的问题的。
我将此值添加到 my.cnf 文件中:
innodb_flush_log_at_trx_commit = 2
在我重启 mysql 服务器后,服务器负载突然下降,更新、插入和删除查询也从大约 0.22222 - 0.91922 秒下降到负载下的 0.000013 秒。 就像之前使用 Myisam 和 Mysql 一样,以及它应该如何使用索引进行如此简单的更新。
我不得不提一下,我已经将所有接收频繁插入或更新命令的表设置为 INNODB,将那些有很多选择的表设置为 ARIA。
由于我们不处理货币交易,如果我们因为以下原因而损失最后几秒对我来说不是问题
innodb_flush_log_at_trx_commit = 2
我go更进一步。 如果我们输掉了最后 30 秒,我也可以接受。
所以我也设置了:
innodb_flush_log_at_timeout = 30
我目前正在测试
innodb_flush_log_at_trx_commit = 0
但到目前为止,我没有看到明显的改善
innodb_flush_log_at_timeout = 30
innodb_flush_log_at_trx_commit = 0
代替
innodb_flush_log_at_timeout = 1 (default)
innodb_flush_log_at_trx_commit = 2
所以主要目标是:
innodb_flush_log_at_trx_commit = 2
or
innodb_flush_log_at_trx_commit = 0
有谁知道,为什么:
innodb_flush_log_at_timeout = 30
innodb_flush_log_at_trx_commit = 0
并不比刚才快
innodb_flush_log_at_trx_commit = 2
?
我也不明白,为什么这个设置没有更受欢迎,因为如果许多网站不介意失去一秒钟或更多时间,他们可以在速度方面有很大的改进。
非常感谢你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.