一个简单的 MySQL 插入/更新怎么会比外部 Web 请求慢?
Posted
技术标签:
【中文标题】一个简单的 MySQL 插入/更新怎么会比外部 Web 请求慢?【英文标题】:How can a simple MySQL insert/update be slower than an external web request? 【发布时间】:2016-03-01 16:32:09 【问题描述】:由于一些性能问题,我一直在优化几个 SQL 查询并向某些表/列添加索引以加快速度。
在 php 中使用 microtime()
运行了一些时间测试(循环查询几百次并在每个循环中调用 RESET QUERY CACHE
)。我对执行 3 件事的函数之一的结果感到有些困惑:
-
在
sessions
表 (InnoDB) 中插入一行。
更新users
表 (InnoDB) 中的一行。
将会话 ID 发送到远程服务器,远程服务器将会话 ID 插入它自己的会话表 (MongoDB)。
步骤 1. 一般需要 30 - 40 ms,步骤 2. 20 - 30 ms,步骤 3. 7 - 20 ms。
我尝试查找 mysql 的一些预期查询时间,但没有发现任何有用的信息,所以我不知道会发生什么。话虽如此,这些查询时间似乎有点长,我肯定不期望 Web 请求完成的速度比 MySQL 查询本地数据库的速度快。
知道这些查询时间与网络请求相比是否合理?
SQL/系统信息
两台服务器(远程服务器和带有 MySQL 数据库的服务器)都是在具有共享存储(多个 SSD RAID 目标)的同一物理服务器上运行的虚拟服务器。远程服务器分配了一个 CPU 和 2 GB RAM,MySQL 服务器分配了 8 个 CPU 和 32 GB RAM。两台服务器都在同一个局域网上。
sessions
插入查询:
INSERT INTO sessions (
session_id,
user_id,
application,
machine_id,
user_agent,
ip,
method,
created,
last_active,
expires
)
VALUES (
string, // session_id
int, // user_id
string, // application
string, // machine_id
string, // user_agent
string, // ip
string, // method
CURRENT_TIMESTAMP, // created
CURRENT_TIMESTAMP, // last_active
NULL / FROM_UNIXTIME([PHP timestamp]) // expires
)
sessions
表(包含 ~500'000 行);
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| sessions_id | int(11) | NO | PRI | NULL | auto_increment |
| session_id | char(32) | NO | UNI | NULL | |
| user_id | int(11) | NO | MUL | NULL | |
| application | varchar(128) | NO | | NULL | |
| machine_id | varchar(36) | NO | | NULL | |
| user_agent | varchar(1024) | NO | | NULL | |
| ip | varchar(15) | NO | | NULL | |
| method | varchar(20) | NO | | NULL | |
| created | datetime | NO | | NULL | |
| last_active | datetime | NO | | NULL | |
| expires | datetime | YES | MUL | NULL | |
+-------------+---------------+------+-----+---------+----------------+
users
更新查询:
UPDATE users
SET last_active = string // For example '2016-01-01 00:00:00'
WHERE user_id = int
users
表(包含 ~200'000 行):
+------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+---------------------+------+-----+---------+----------------+
| user_id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(64) | NO | MUL | NULL | |
| first_name | varchar(256) | NO | | NULL | |
| last_name | varchar(256) | NO | | NULL | |
| info | varchar(512) | NO | | NULL | |
| address1 | varchar(512) | NO | | NULL | |
| address2 | varchar(512) | NO | | NULL | |
| city | varchar(256) | NO | | NULL | |
| zip_code | varchar(128) | NO | | NULL | |
| state | varchar(256) | NO | | NULL | |
| country | varchar(128) | NO | | NULL | |
| locale | varchar(5) | NO | | NULL | |
| phone | varchar(128) | NO | | NULL | |
| email | varchar(256) | NO | MUL | NULL | |
| password | char(60) | NO | MUL | NULL | |
| permissions | bigint(20) unsigned | NO | | 0 | |
| created | datetime | YES | | NULL | |
| last_active | datetime | YES | | NULL | |
+------------------------+---------------------+------+-----+---------+----------------+
【问题讨论】:
远程服务器数据库有多大? 整个数据库大约 45 GB,但会话表大约有 600'000 行。我只是希望 Web 请求的套接字和 TCP 开销比将几百字节写入/更新到本地 MySQL 慢。 在这两种情况下,打开套接字、写入套接字和取回数据的开销是相同的(因为 MySQL 也作为服务运行)。唯一的区别是查询执行时间和数据的传输时间。如果传输时间非常短(很可能是现代连接),那么归结为哪种类型的数据库可以更快地完成。也许 Mongo 只是在这种事情上更快。 从个人测试来看,我可以说是的,Mongo 在插入查询中几乎总是胜过 MySQL。不过,更新查询在主键上写入带有WHERE
的时间戳的 20-30 毫秒似乎仍然很慢。
【参考方案1】:
似乎问题只是我们的 MySQL 设置(它们都是默认设置)。
我在 users
更新查询上运行 MySQL 配置文件,发现步骤 query end
占用了执行查询的大部分时间。
谷歌搜索导致我找到https://***.com/a/12446986/736247 - 而不是直接使用所有建议的值(不推荐,因为其中一些会对数据完整性产生不利影响)我找到了更多信息,包括 Percona 上的这个页面: https://www.percona.com/blog/2013/09/20/innodb-performance-optimization-basics-updated/.
InnoDB 启动选项和系统变量也很有用:http://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html 也很有用。
我最终为以下设置设置了新值:
innodb_flush_log_at_trx_commit
innodb_flush_method
innodb_buffer_pool_size
innodb_buffer_pool_instances
innodb_log_file_size
这导致查询时间显着缩短(测量方式与我在问题中所做的相同):
-
在
sessions
表中插入一行:~8 ms(从 30-40 ms 减少)。
更新users
表中的一行:~2.5 ms(从 20-30 ms 下调)。
【讨论】:
以上是关于一个简单的 MySQL 插入/更新怎么会比外部 Web 请求慢?的主要内容,如果未能解决你的问题,请参考以下文章