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 上有一个您并不真正需要的索引)
可能就像 SELECT
在 users
中搜索某物一样简单。 注意,InnoDB不会遇到这个问题。
MyISAM
在执行 UPDATE
、INSERT
或 DELETE
时必然会执行 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
?
我也不明白,为什么这个设置没有更受欢迎,因为如果他们不介意失去一秒钟或更多时间,许多网站可以在速度方面有很大的改进。
非常感谢。
我们的服务器已使用 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 上有一个您并不真正需要的索引)
可能就像 SELECT
在 users
中搜索某物一样简单。 注意,InnoDB不会遇到这个问题。
MyISAM
在执行 UPDATE
、INSERT
或 DELETE
时必然会执行 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
?
我也不明白,为什么这个设置没有更受欢迎,因为如果他们不介意失去一秒钟或更多时间,许多网站可以在速度方面有很大的改进。
非常感谢。