Ale*_*xis 4 mysql performance optimization mysql-5.7 query-performance
通常我必须在获取其他非相关行的查询中返回某些行的计数。
例如一个表用户一个表评论和一个表图片
User:
id
nickname
Review:
id
to_user_id
from_user_id
rating
Picture:
id:
user_id
url
Run Code Online (Sandbox Code Playgroud)
假设我想在一个查询中检索“给定”userId 的所有图片 url 的昵称以及评论该用户的人数。
我认为在执行此查询时的第一种也是简单的方法是:
SELECT
u.nickname
(SELECT count(*) FROM review WHERE to_user_id = u.id) as reviewCount,
p.url
FROM user
LEFT JOIN picture ON p.user_id = u.id
WHERE
u.id = 1
Run Code Online (Sandbox Code Playgroud)
这样做的另一种方法是没有那个子选择并通过在正确的 user_id 上加入评论表
SELECT
u.nickname,
r.reviewCount,
p.url
FROM user u
LEFT JOIN (
SELECT to_user_id, count(*) reviewCount FROM review GROUP BY to_user_id
) r ON r.to_user_id = u.id
LEFT JOIN picture ON p.user_id = u.id
WHERE u.id = 1;
Run Code Online (Sandbox Code Playgroud)
我不是数据库查询性能和调优方面的专家。如果一个解决方案比另一个更好,有人可以向我解释吗?(或者如果有其他更好的解决方案)?
编辑: 抱歉忘了提及。我正在使用最新的 MySQL
您没有指定您正在使用哪个 RDBMS。我在这里写的大部分内容应该是相当独立的,但我主要有 MySQL 的经验,所以也许不同的系统允许一些其他优化。
这(SELECT count(*) FROM review WHERE to_user_id = u.id) as reviewCount
是一个依赖子查询- 它将为结果中的每一行执行。即使一个执行速度很快,潜在的数千个执行也会使它变慢。
中的一个JOIN
是派生表- 它只会执行一次并具体化到一个临时表中,然后该临时表将连接到您的其他表。如果查询速度很快(可以使用 index on (to_user_id)
),那很好。但在这种情况下,即使对于没有真正显示在结果中的用户,计数也会被计算在内。但是..你可以把条件放在那里(to_user_id = 1
而不是GROUP BY)。
但是为了让事情变得不那么简单,新版本中存在一些优化。通过在 MariaDB 10(和 IIRC MySQL 5.7,但我没有验证)中使用子查询缓存,可以使依赖子查询更快。这意味着在您的情况下,结果中的所有行都具有u.id = 1
->to_user_id = 1
并且子查询实际上只会执行一次,然后将使用缓存的结果。如果可用,则两个版本之间的差异将很小。
就我个人而言,大多数时候我更喜欢你的第二个版本,但在某些情况下,第一个版本会更快 - 我曾经有一个查询,它不能简单地以正确的方式限制 JOINED 子查询中的行,而是切换到依赖子查询实际上只读取了几个唯一的组合。
归档时间: |
|
查看次数: |
9877 次 |
最近记录: |