使用 EXPLAIN 输出优化慢 MySQL 查询
optimizing a Slow MySQL query using EXPLAIN output
以下查询用了 6.6 秒 运行,并产生了 26 行。
EXPLAIN 结果是两个 'ref' 类型的简单查询,使用键,扫描 23 行和 48 行。
Table f 有 1000 行,table m 有 42000 行。
seltype table type keys key keylen ref rows filtered extra
SIMPLE f ref PRIMARY, forum_site_id 4 const 23 100.00 Using where; Using temporary; Using filesort
forum_site_id,
forums_flag_list_new_posts
SIMPLE m ref forum_msg_forum_id, forum_msg_forum_id 5 locali_db.f.id 48 100.00 Using where
forum_msg_status,
forum_msg_date
这里是查询(很简单的一个):
SELECT
m.id AS msg_id,
m.public_id AS msg_public_id,
more fileds of this table ...
f.id AS forum_id,
f.public_id AS forum_public_id,
more fileds of this table ...
FROM
forum_msgs m
INNER JOIN forums f ON
m.forum_id = f.id
WHERE
f.site_id = 19
AND f.flag_list_new_posts = 1
AND m.msg_date >= 1434803744
AND m.status <> 11
ORDER BY
m.msg_date DESC
LIMIT
100
WHERE 和ORDER BY 子句中的所有字段都是INTEGER 类型并定义为INDEX。字段 forum_id 定义为 FOREIGN KEY。
我很乐意找出可能导致异常表现的原因:)
您的查询基本上是:
SELECT m.*, f.*
FROM forum_msgs m INNER JOIN
forums f
ON m.forum_id = f.id
WHERE f.site_id = 19 AND
f.flag_list_new_posts = 1 AND
m.msg_date >= 1434803744 AND
m.status <> 11
ORDER BY m.msg_date DESC
LIMIT 100;
这表明以下索引:forums(site_id, flag_list_new_posts, id)
和 forum_msgs(forum_id, msg_date, status)
。
我认为没有办法绕过 order by
的文件排序。
INDEX(msg_date)
可能 欺骗优化器从 m
开始并避免对 ORDER BY
.
进行排序
(提问性能问题时请提供SHOW CREATE TABLE
。)
但是排序并不是代价高昂的部分。代价高昂的部分可能是随机提取到 m
。显然缓存是冷的。
EXPLAIN
估计大约有 1000 次读取 (23*48),但这可能会很严重 under/overestimated。如果 m
没有很好地缓存,那可能是 1000 次磁盘命中,这很容易花费 6.6 秒。
如果您使用的是 InnoDB,innodb_buffer_pool_size
应该是 可用 RAM 的大约 70%。
数据库在 RDS 上 运行,具有相当高的 QPS(峰值高达 200)。平均导致 50 IOP/s 到磁盘。将实例存储类型从磁性更改为通用 SSD 解决了这个问题。
以下查询用了 6.6 秒 运行,并产生了 26 行。
EXPLAIN 结果是两个 'ref' 类型的简单查询,使用键,扫描 23 行和 48 行。
Table f 有 1000 行,table m 有 42000 行。
seltype table type keys key keylen ref rows filtered extra SIMPLE f ref PRIMARY, forum_site_id 4 const 23 100.00 Using where; Using temporary; Using filesort forum_site_id, forums_flag_list_new_posts SIMPLE m ref forum_msg_forum_id, forum_msg_forum_id 5 locali_db.f.id 48 100.00 Using where forum_msg_status, forum_msg_date
这里是查询(很简单的一个):
SELECT
m.id AS msg_id,
m.public_id AS msg_public_id,
more fileds of this table ...
f.id AS forum_id,
f.public_id AS forum_public_id,
more fileds of this table ...
FROM
forum_msgs m
INNER JOIN forums f ON
m.forum_id = f.id
WHERE
f.site_id = 19
AND f.flag_list_new_posts = 1
AND m.msg_date >= 1434803744
AND m.status <> 11
ORDER BY
m.msg_date DESC
LIMIT
100
WHERE 和ORDER BY 子句中的所有字段都是INTEGER 类型并定义为INDEX。字段 forum_id 定义为 FOREIGN KEY。
我很乐意找出可能导致异常表现的原因:)
您的查询基本上是:
SELECT m.*, f.*
FROM forum_msgs m INNER JOIN
forums f
ON m.forum_id = f.id
WHERE f.site_id = 19 AND
f.flag_list_new_posts = 1 AND
m.msg_date >= 1434803744 AND
m.status <> 11
ORDER BY m.msg_date DESC
LIMIT 100;
这表明以下索引:forums(site_id, flag_list_new_posts, id)
和 forum_msgs(forum_id, msg_date, status)
。
我认为没有办法绕过 order by
的文件排序。
INDEX(msg_date)
可能 欺骗优化器从 m
开始并避免对 ORDER BY
.
(提问性能问题时请提供SHOW CREATE TABLE
。)
但是排序并不是代价高昂的部分。代价高昂的部分可能是随机提取到 m
。显然缓存是冷的。
EXPLAIN
估计大约有 1000 次读取 (23*48),但这可能会很严重 under/overestimated。如果 m
没有很好地缓存,那可能是 1000 次磁盘命中,这很容易花费 6.6 秒。
如果您使用的是 InnoDB,innodb_buffer_pool_size
应该是 可用 RAM 的大约 70%。
数据库在 RDS 上 运行,具有相当高的 QPS(峰值高达 200)。平均导致 50 IOP/s 到磁盘。将实例存储类型从磁性更改为通用 SSD 解决了这个问题。