我的 MySQL 应用程序在运行一些,和查询时遇到性能下降的问题。在这个问题中,我将只讨论一个特定的 ,因为它足以证明问题:UPDATE
INSERT
DELETE
UPDATE
UPDATE projects SET ring = 5 WHERE id = 1
这UPDATE
通常足够快,大约 0.2 毫秒,但时不时地(足以成为问题)需要几秒钟。这是日志的摘录(查看第 4 行):
~ (0.000282) UPDATE `projects` SET `ring` = 5 WHERE `id` = 1
~ (0.000214) UPDATE `projects` SET `ring` = 6 WHERE `id` = 1
~ (0.000238) UPDATE `projects` SET `ring` = 7 WHERE `id` = 1
~ (3.986502) UPDATE `projects` SET `ring` = 8 WHERE `id` = 1
~ (0.000186) UPDATE `projects` SET `ring` = 9 WHERE `id` = 1
~ (0.000217) UPDATE `projects` SET `ring` = 0 WHERE `id` = 1
~ (0.000162) UPDATE `projects` SET `ring` = 1 WHERE `id` = 1
projects
是一个 InnoDB 表,有 6 列类型INT
和VARCHAR
17 行和一个索引id
。它也发生在其他桌子上,但在这里我专注于这张桌子。在尝试解决问题时,我确保查询都是顺序的,所以这不是锁定问题。UPDATE
以上是在事务的上下文中执行的。服务器上的其他信息:
- 具有 4GB RAM(原为 1GB)、12GB 可用磁盘空间的 VPS
- CentOS 5.8(原为 5.7)
- MySQL 5.5.10(原为 5.0.x)
上面的“是”位表示它在升级之前或之后都不起作用。
到目前为止我已经尝试过,但无济于事:
- 设置
innodb_flush_log_at_trx_commit
为 0、1 或 2 - 设置
innodb_locks_unsafe_for_binlog
开启或关闭 - 设置
timed_mutexes
开启或关闭 innodb_flush_method
从默认更改为O_DSYNC
或O_DIRECT
- 从默认增加到600M
innodb_buffer_pool_size
再增加到 3000M innodb_log_file_size
从默认增加到128M- 从源代码编译 MySQL
- Running
SHOW PROCESSLIST
,它告诉我状态正在“更新” - Running
SHOW PROFILE ALL
,表示几乎所有时间都花在“更新”上,并且在该步骤中,没有太多时间花在 CPU 周期上,并且有很多自愿的上下文切换(比如 30 次) - 监控.
SHOW STATUS
_Innodb_buffer_pool_pages_dirty
被刷新的脏页和慢查询之间可能存在一些关系,但相关性并不清楚。
然后我决定用 . 检查系统的 I/O 延迟ioping
。这是我的第一个 VPS,所以看到这个结果我很惊讶:
4096 bytes from . (vzfs /dev/vzfs): request=1 time=249.2 ms
4096 bytes from . (vzfs /dev/vzfs): request=2 time=12.3 ms
4096 bytes from . (vzfs /dev/vzfs): request=3 time=110.5 ms
4096 bytes from . (vzfs /dev/vzfs): request=4 time=232.8 ms
4096 bytes from . (vzfs /dev/vzfs): request=5 time=294.4 ms
4096 bytes from . (vzfs /dev/vzfs): request=6 time=704.7 ms
4096 bytes from . (vzfs /dev/vzfs): request=7 time=1115.0 ms
4096 bytes from . (vzfs /dev/vzfs): request=8 time=209.7 ms
4096 bytes from . (vzfs /dev/vzfs): request=9 time=64.2 ms
4096 bytes from . (vzfs /dev/vzfs): request=10 time=396.2 ms
相当不稳定,我会说。
说了这么多,我问:
I/O 延迟是否会偶尔影响 MySQL 的性能?我一直认为,当您运行 时
UPDATE
,处理该连接的线程不会将数据刷新到磁盘或等待这样的刷新;它会立即返回,并且刷新将由另一个线程在另一个时间完成。如果它不能是磁盘 I/O,除了租用专用服务器之外,我还有什么可以尝试的吗?