MySQL 查询在迁移到 RDS 后停留在“发送数据”中 30 秒
Posted
技术标签:
【中文标题】MySQL 查询在迁移到 RDS 后停留在“发送数据”中 30 秒【英文标题】:MySQL queries stuck in "sending data" for 30 seconds after migrating to RDS 【发布时间】:2017-11-22 22:22:57 【问题描述】:当 mysql 在与网站其余部分相同的 EC2 实例上本地时,此查询(以及我认为有相关问题的其他一些查询)不需要 30 秒。更像是毫秒。
有什么不好看的吗?
SELECT *, chv_images.image_id FROM chv_images
LEFT JOIN chv_storages ON chv_images.image_storage_id =
chv_storages.storage_id
LEFT JOIN chv_users ON chv_images.image_user_id = chv_users.user_id
LEFT JOIN chv_albums ON chv_images.image_album_id = chv_albums.album_id
LEFT JOIN chv_categories ON chv_images.image_category_id =
chv_categories.category_id
LEFT JOIN chv_meta ON chv_images.image_id = chv_meta.image_id
LEFT JOIN chv_likes ON chv_likes.like_content_type = "image" AND
chv_likes.like_content_id = chv_images.image_id AND chv_likes.like_user_id = 1
LEFT JOIN chv_follows ON chv_follows.follow_followed_user_id =
chv_images.image_user_id
LEFT JOIN chv_follows_projects ON
chv_follows_projects.follows_project_project_id =
chv_images.image_project_id LEFT JOIN chv_projects ON
chv_projects.project_id = follows_project_project_id WHERE
chv_follows.follow_user_id='1' OR (follows_project_user_id = 1 AND
chv_projects.project_privacy = "public" AND
chv_projects.project_is_public_upload = 1) GROUP BY chv_images.image_id
ORDER BY chv_images.image_id DESC
LIMIT 0,15
And this is what EXPLAIN shows:
谢谢
更新:这个查询有同样的问题。它没有 GROUP BY。
SELECT *, chv_images.image_id FROM chv_images
LEFT JOIN chv_storages ON chv_images.image_storage_id =
chv_storages.storage_id
LEFT JOIN chv_users ON chv_images.image_user_id = chv_users.user_id
LEFT JOIN chv_albums ON chv_images.image_album_id = chv_albums.album_id
LEFT JOIN chv_categories ON chv_images.image_category_id =
chv_categories.category_id
LEFT JOIN chv_meta ON chv_images.image_id = chv_meta.image_id
LEFT JOIN chv_likes ON chv_likes.like_content_type = "image" AND
chv_likes.like_content_id = chv_images.image_id AND chv_likes.like_user_id = 1
ORDER BY chv_images.image_id DESC
LIMIT 0,15
【问题讨论】:
欢迎来到 Stack Overflow!您可能没有意识到,当您提出查询优化问题时,最好将SHOW CREATE TABLE
的输出包含在查询中的所有表中。这将帮助回答您问题的人了解您使用了哪些数据类型、索引和约束。帮助我们帮助您!
您好 Bill,SHOW CREATE TABLE 查询出错。 #1064.
您是否将表名作为参数提供?见dev.mysql.com/doc/refman/5.7/en/show-create-table.html
提供表名时,不会报错,但在phpmyadmin中也不会提供结果。
follows_project_user_id
在哪个表中?
【参考方案1】:
EXPLAIN 显示了几个表扫描 (type: ALL
),因此它需要超过 30 秒也就不足为奇了。
这是您的解释:
注意rows
列显示了从第一个表 chv_images 中读取的估计 14420 行。它正在对所有行进行表扫描。
一般来说,当你进行一系列的 JOIN 操作时,你可以将 EXPLAIN 的 rows
列中的所有值相乘,最终的结果就是 MySQL 要做多少行读取。在这种情况下,它是 14420 * 2 * 1 * 1 * 2 * 1 * 916 或 52,834,880 行读取。这应该考虑到在同一个查询中执行多个表扫描的高成本。
您可以通过在这些表上创建一些索引来帮助避免这些表扫描:
ALTER TABLE chv_storages
ADD INDEX (storage_id);
ALTER TABLE chv_categories
ADD INDEX (category_id);
ALTER TABLE chv_likes
ADD INDEX (like_content_id, like_content_type, like_user_id);
尝试创建这些索引,然后再次运行 EXPLAIN。
其他表已经通过主键 (type: eq_ref
) 或辅助键 (type: ref
) 进行查找,因此这些表已经过优化。
您的 EXPLAIN 显示您的查询使用临时表和文件排序。您应该重新考虑是否需要 GROUP BY,因为这可能会导致额外的工作。
另一个提示是避免使用SELECT *
,因为它可能会强制查询读取许多您不需要的额外列。相反,只明确命名您需要的列。
【讨论】:
我运行了上面的查询,但什么也没发生。没有绿色或红色。 我对以下类似查询有同样的问题: 当你说绿色或红色时,我不知道你在说什么。我不使用 MySQL 的 GUI 工具。你是说ADD INDEX
没有执行?
我正在使用 phpymyadmin,所以我指的是查询处理或错误处理。您的查询建议没有说它做了任何事情,再次运行它不会给出错误,说它已经添加了索引。
需要明确的是,运行查询后 EXPLAIN 中没有键。应该有吗?【参考方案2】:
chv_images 中有索引吗?
我提议:
CREATE INDEX idx_image_id ON chv_images (image_id);
【讨论】:
我运行了这个查询,但对 EXPLAIN 没有明显的变化。【参考方案3】:(Bill 的想法很好。我会换个方式讨论……)
Explode-Implode --如果LEFT JOINs
匹配不超过1行,例如改变,
SELECT
...
LEFT JOIN chv_meta ON chv_images.image_id = chv_meta.image_id
进入
SELECT ...,
( SELECT foo FROM chv_meta WHERE image_id = chv_images.image_id ) AS foo, ...
如果可以为 所有JOINs
做到这一点,您可以摆脱 GROUP BY
。这将避免代价高昂的“explode-implode”,其中JOINs
导致更多行,然后GROUP BY
摆脱了重复。 (我怀疑你不能把所有的连接都移进去。)
OR -> UNION -- OR
很难优化。您的查询看起来很适合转换为 UNION
,然后生成更多有用的索引。
WHERE chv_follows.follow_user_id='1'
OR (follows_project_user_id = 1
AND chv_projects.project_privacy = "public"
AND chv_projects.project_is_public_upload = 1
)
假设follows_project_user_id
在`chv_images中,
( SELECT ...
WHERE chv_follows.follow_user_id='1' )
UNION DISTINCT -- or ALL, if you are sure there won't be dups
( SELECT ...
WHERE follows_project_user_id = 1
AND chv_projects.project_privacy = "public"
AND chv_projects.project_is_public_upload = 1 )
需要的索引:
chv_follows: (follow_user_id)
chv_projects: (project_privacy, project_is_public_upload) -- either order
但这还没有处理ORDER BY
和LIMIT
。此类的一般模式:
( SELECT ... ORDER BY ... LIMIT 15 )
UNION
( SELECT ... ORDER BY ... LIMIT 15 )
ORDER BY ... LIMIT 15
是的,ORDER BY
和 LIMIT
重复了。
这适用于第 1 页。如果您想要接下来的 15 行,请参阅http://mysql.rjweb.org/doc.php/pagination#pagination_and_union
在构建这两个子选择之后,查看它们;我认为您将能够优化每一个,并且可能需要新的索引,因为优化器将从不同的“第一个”表开始。
【讨论】:
以上是关于MySQL 查询在迁移到 RDS 后停留在“发送数据”中 30 秒的主要内容,如果未能解决你的问题,请参考以下文章
RDS MySQL云原生中间件在网易的实践-3306π南京站