MariaDB 下的缓慢更新、删除和插入查询

Slow Update, Delete and Insert Queries under MariaDB

我们的服务器已使用 MariaDB 从 Ubuntu 16 更新到 Ubuntu 20。不幸的是,网站的加载时间变慢了。通常 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。

我不知道是什么原因。你呢?

非常感谢。

当您使用 MariaDB 时,您可以使用像 EverSQL 这样的工具来查找丢失的索引或发现冗余索引(例如,您在 user_video_count 上有一个您并不真正需要的索引)

可能就像 SELECTusers 中搜索某物一样简单。 注意,InnoDB不会遇到这个问题。

MyISAM 在执行 UPDATEINSERTDELETE 时必然会执行 table 锁定 。 (还有 ALTER 和其他 DDL 语句。)如果有很多连接执行任何混合写入甚至 SELECTs,锁可以级联很长时间。

真正的解决方案,无论是在 MariaDB 还是 [特别是] MySQL 中,都是切换到 InnoDB。

如果这是对“喜欢”或“观看次数”进行大量计数的情况,则部分解决方案(在任一引擎中)是将此类计数器放在单独的并行 table 中。这避免了那些简单快速的更新与主要 table 上的其他操作发生冲突。在人流量极高的区域,收集此类增量并分批应用它们是有必要的。我认为您的卷不需要那种激进的解决方案。

MySQL 有 all-but-eliminated MyISAM。 MariaDB 可能会在几年内效仿。

解决这个问题:

the same query in myphpadmin its really fast

问题不在于你如何 运行 它,而在于同时发生的其他事情。

LOW PRIORITY 是一个有时有效的 MyISAM-specific 组合。)

MyISAM 执行“table 锁定”; InnoDB 做“行锁定”。因此,Innodb 可以在 table 上执行许多“同时”操作,而 MyISAM 会在写入发生时立即序列化。

更多(现在关注InnoDB。)

可能涉及到的其他一些事情

如果两个 UPDATEs 试图同时修改 同一行 ,一个将不得不等待(由于行锁定)。

如果确实有很多事情在进行,延迟可能会级联。如果在一个实例中有 20 个连接处于活动状态 运行ning,则它们各自都会减慢彼此的速度。每个连接都被公平分配,但这意味着它们都变慢了。

SHOW PROCESSLIST 看看什么是 运行ning -- 不是“睡眠”。 “Time”最高的进程(系统线程除外)很可能是这场闹剧的始作俑者

slowlog 有助于更深入地研究。我以足够低的 long_query_time 打开它并等待 'event' 发生。然后我使用 pt-query-digest(或 mydumpslow -s t)找出最慢的查询。通过更多的努力,人们可能会注意到有很多查询在某一瞬间“缓慢”——甚至可能是“点查询”(如 UPDATE ... WHERE id=constant)出乎意料地 运行ning 比 long_query_time。这表示查询太多 and/or 一些查询意外地锁定了行。 (注意:查询的“时间戳”是查询 结束时 ;减去 Query_time 得到开始。) SlowLog

更多

正如您所发现的,

innodb_flush_log_at_trx_commit = 2 在快速执行大量 single-query 事务时是一个很好的解决方法。如果该修复的频率变得太大,那么我上面的评论可能是必要的。

=2 和 =0 之间不会有太大的性能差异。

至于innodb_flush_log_at_timeout。请提供`SHOW GLOBAL STATUS LIKE 'Binlog%commits'

至于innodb_lock_wait_timeout...我认为更改不会对您有帮助。如果您的查询之一由于该超时而中止,您应该记录它发生并重试事务。

听起来您 运行 autocommit = ON 没有使用显式事务?很好(对于 non-money activity)。在某些情况下,使用事务可以帮助提高性能——例如人为地将多个查询批处理在一起以避免某些 I/O。缺点是与其他连接发生冲突的可能性增加。尽管如此,如果您始终检查错误并重新运行调整'transaction',一切都应该很好。

innodb_flush_log_at_trx_commit

当该设置为“1”(可能是您最初的设置)时,每个更新都会额外写入磁盘以确保数据完整性。如果磁盘是 HDD(而非 SDD),则每次更新会增加大约 10 毫秒,因此导致最大值约为 100 updates/second。有几种解决方法。

  • innodb_flush_log_at_trx_commit = 0 or 2,牺牲了一些数据的完整性。
  • 人为地将多个更新合并到一个事务中,从而将 10 毫秒分散到多个查询中。
  • 根据它们正在做的事情明确组合多个更新and/or它们接触的行。 (在真正繁忙的系统中,这可能涉及其他服务器 and/or 其他 table。)
  • 将计数器移动到另一个 table(见上文)——这允许在主要 table 上进行更多 time-consuming 操作的干扰。 (我没有听到一个明确的例子,但 slowlog 可能已经指出了这一点。)
  • 切换到 SSD 驱动器 -- 更新容量可能增加 10 倍。

我怀疑社交媒体巨头会做上述所有事情。

首先感谢所有帮助过我的人。我真的很感激人们尝试投入宝贵的时间。

我想告诉您我是如何设法解决更新、插入和删除查询缓慢的问题的。

我将此值添加到 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 

我更进一步。如果我们在失败中失去最后 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

?

我也不明白,为什么这个设置没有更受欢迎,因为如果他们不介意失去一秒钟或更多时间,许多网站可以在速度方面有很大的改进。

非常感谢。