【问题标题】:MySQL update queries slowed across all databasesMySQL 更新查询在所有数据库中都变慢了
【发布时间】:2016-11-16 17:13:42
【问题描述】:

我有一个运行普通 LAMP 堆栈的 ubuntu 服务器(2 个 3.0Ghz 四核、16GB 内存和 15k sas 驱动器上的 raid 1),其中大约 5 个客户端每秒连接到一个 php 脚本。客户端会传递少量信息,这些数据会在 MySQL 数据库中更新。

在服务器的后台,我有一个 php 脚本每秒检查一次数据并更新数据库。

只有几条记录被反复更新,没有插入,所以表的大小真的很小(最多 4 行)。

也就是说,我通常会打开一个 ssh 会话来观察后台脚本的运行速度。在使用 SELECT 和 UPDATE 查询直接运行一个月后,每次查询大约需要 100 微秒(0.0001 秒),突然 UPDATE 开始每次查询需要 20000+ 微秒(0.02 秒),无论使用什么数据库,使用或更新什么列(主键或其他)等我已经重新启动了一切,包括服务器,删除了我所有的数据库(只有我创建的那些,而不是系统数据库),阻止了客户端,从控制台 mysql 和 PhpMyAdmin 运行查询,结果是一样的。

这是一个示例,在没有负载或客户端连接到服务器的情况下从控制台运行:

mysql> CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8 */;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE TABLE `test` (
  `idtest` int(11) NOT NULL AUTO_INCREMENT,
  `field1` varchar(64) NOT NULL,
  `field2` varchar(64) NOT NULL,
  `field3` int(11) NOT NULL,
  PRIMARY KEY (`idtest`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.14 sec)

mysql> INSERT INTO `test`.`test` (`idtest`, `field1`, `field2`, `field3`) VALUES (NULL, 'Testing', 'None', '0');
Query OK, 1 row affected (0.02 sec)

mysql> SELECT * FROM test;
+--------+---------+--------+--------+
| idtest | field1  | field2 | field3 |
+--------+---------+--------+--------+
|      1 | Testing | None   |      0 |
+--------+---------+--------+--------+
1 row in set (0.00 sec)

mysql> UPDATE `test`.`test` SET `field3` = '1' WHERE `test`.`idtest` = 1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

从上面的示例中,INSERT 似乎也受到了影响。我已经在另一台服务器上运行了上面相同的查询,其资源约为 1/10,并且正如预期的那样,它在 100 到 200 微秒内运行查询。我怀疑它与 InnoDB 缓存有关,但我可能是错的。

以下是有关服务器和 MySQL 的一些信息:

平均负载:平均负载:0.04、0.04、0.05

服务器:通过 UNIX 套接字的本地主机

服务器类型:MySQL

服务器版本:5.6.28-0ubuntu0.15.04.1 - (Ubuntu)

协议版本:10

用户:root@localhost

服务器字符集:UTF-8 Unicode (utf8)

mysql> SHOW VARIABLES LIKE '%query%';
+------------------------------+-----------------------------------+
| Variable_name                | Value                             |
+------------------------------+-----------------------------------+
| binlog_rows_query_log_events | OFF                               |
| ft_query_expansion_limit     | 20                                |
| have_query_cache             | YES                               |
| long_query_time              | 10.000000                         |
| query_alloc_block_size       | 8192                              |
| query_cache_limit            | 1048576                           |
| query_cache_min_res_unit     | 4096                              |
| query_cache_size             | 16777216                          |
| query_cache_type             | OFF                               |
| query_cache_wlock_invalidate | OFF                               |
| query_prealloc_size          | 8192                              |
| slow_query_log               | OFF                               |
| slow_query_log_file          | /var/lib/mysql/xxxxx-slow.log |
+------------------------------+-----------------------------------+
13 rows in set (0.00 sec)

mysql> SHOW VARIABLES LIKE '%cache%';
+--------------------------------+----------------------+
| Variable_name                  | Value                |
+--------------------------------+----------------------+
| binlog_cache_size              | 32768                |
| binlog_stmt_cache_size         | 32768                |
| have_query_cache               | YES                  |
| host_cache_size                | 279                  |
| innodb_disable_sort_file_cache | OFF                  |
| innodb_ft_cache_size           | 8000000              |
| innodb_ft_result_cache_limit   | 2000000000           |
| innodb_ft_total_cache_size     | 640000000            |
| key_cache_age_threshold        | 300                  |
| key_cache_block_size           | 1024                 |
| key_cache_division_limit       | 100                  |
| max_binlog_cache_size          | 18446744073709547520 |
| max_binlog_stmt_cache_size     | 18446744073709547520 |
| metadata_locks_cache_size      | 1024                 |
| query_cache_limit              | 1048576              |
| query_cache_min_res_unit       | 4096                 |
| query_cache_size               | 16777216             |
| query_cache_type               | OFF                  |
| query_cache_wlock_invalidate   | OFF                  |
| stored_program_cache           | 256                  |
| table_definition_cache         | 615                  |
| table_open_cache               | 431                  |
| table_open_cache_instances     | 1                    |
| thread_cache_size              | 8                    |
+--------------------------------+----------------------+
24 rows in set (0.00 sec)

我的.cnf:

[mysqld]
innodb_autoinc_lock_mode=0

最后:

ubuntu@xxxxx:~$ df
Filesystem                     1K-blocks    Used Available Use% Mounted on
udev                             8202368       0   8202368   0% /dev
tmpfs                            1642808    9600   1633208   1% /run
/dev/mapper/xxxxx--vg-root  53035144 7827988  42490076  16% /
tmpfs                            8214020       0   8214020   0% /dev/shm
tmpfs                               5120       0      5120   0% /run/lock
tmpfs                            8214020       0   8214020   0%     /sys/fs/cgroup
/dev/sda1                         240972  112893    115638  50% /boot
tmpfs                            1642808       0   1642808   0% /run/user/1000

有什么想法吗?提前感谢您的帮助!

更新编辑:

鉴于问题的出现非常奇怪和突然,我开始怀疑它可能与硬件有关。

我从服务器中完全清除了 MySQL 并从存储库中重新安装,它对情况没有影响。我在 Perc6i 上使用两个 15k sas 驱动器运行 raid 1 - 我将从那里开始。这可能最终导致更多的 ServerFault 问题而不是 StackOverflow。我会在进行更多挖掘后报告。

【问题讨论】:

  • 您是否尝试过从 linux 终端运行 top 命令来查看 mysql 进程 ID 在做什么?什么是 memory% 使用率和什么是 cpu%
  • 您的服务器设置有些复杂,尤其是 RAID。在这样的服务器上安装 mysql 之前,您需要先了解一些知识。有时间可以看看这本书203.157.240.9/pub/docs/High.Performance.MySQL.3rd.Edition.pdf
  • 如果您正在寻找最佳性能,您可能想在 freebsd 上尝试一下。 webcodingstudio.com/blog/…

标签: php mysql database


【解决方案1】:

如果它突然开始花费更长的时间,我会想到几件事。

我不会继续谈论显而易见的事情,例如可能依赖于实现同步更新的锁定机制。

我认为您已经超过了文件大小阈值,您现在需要双间接磁盘块寻址而不是单间接块寻址。这意味着按逻辑顺序获取下一个磁盘块的每个单独调用都会慢得多。每一个实际的 I/O 都会受到惩罚。我指的是 ACTUAL I/O,就像一些输出并命中磁盘块哈希队列的东西,这需要(在某些时候)对磁盘控制器执行任务,而不仅仅是说 read() 和拉取已经预取的数据最后一个磁盘 I/O。

这只是猜测。

你真的对 20,000 微秒 = 0.2 毫秒感到不安吗?

【讨论】:

  • 我考虑过锁定和相关问题,但问题仍然存在,除了控制台之外没有连接任何客户端。此外,数据库大小低于 500kb,所以我不确定文件大小会在哪里发挥作用,除了日志。最后,虽然 20,000 usec 被认为是很短的时间,但当我在后台脚本中每次迭代(每秒一次)执行 20 次更新时,肉眼会注意到它。
【解决方案2】:

如果您想提高更新速度,请考虑使用char instead of varchar 字段并在您用于在where 子句中进行比较的字段上创建unclustered indexes

另外,不要通过运行一个查询来衡量您的更新速度,因为在更新查询中,如果您有一个机械硬盘驱动器,spin up time 可能会影响结果。 Windows 也可以缓存数据库文件并提供来自 ram 的数据。禁用 superfetch 服务和run loops 以测试启动延迟。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多