New*_*ewt 5 mysql optimization join
我正在尝试确定查询具有大量数据的连接的两个表的最佳通用方法,其中每个表在 where 子句中都有一列。想象一个带有两个表的简单模式:
posts
id (int)
blog_id (int)
published_date (datetime)
title (varchar)
body (text)
posts_tags
post_id (int)
tag_id (int)
Run Code Online (Sandbox Code Playgroud)
具有以下索引:
posts: [blog_id, published_date]
tags: [tag_id, post_id]
Run Code Online (Sandbox Code Playgroud)
我们想要选择给定博客上标记为“foo”的 10 篇最新帖子。为便于讨论,假设该博客有 1000 万篇帖子,其中 100 万篇被标记为“foo”。查询此数据的最有效方法是什么?
天真的方法是这样做:
SELECT
id, blog_id, published_date, title, body
FROM
posts p
INNER JOIN
posts_tags pt
ON pt.post_id = p.id
WHERE
p.blog_id = 1
AND pt.tag_id = 1
ORDER BY
p.published_date DESC
LIMIT 10
Run Code Online (Sandbox Code Playgroud)
MySQL 将使用我们的索引,但最终仍会扫描数百万条记录。是否有更有效的方法来检索此数据而无需对架构进行非规范化?
最有可能的是,MySQL 将首先使用索引(blog_id, published_date)来扫描所有满足条件的行,blog_id = 1从最新的行开始published_date。为此,只需从正确的位置开始向后扫描索引即可。对于每一行,它必须连接到表posts_tags。此时, 和tag_id都是post_id已知的,因此只需在主索引中查找以查看该行是否存在。10% 的行具有标记,foo因此posts
在找到结果集的前 10 行之前,平均需要检查表中大约 100 行。
如果标签foo很常见,我希望您发布的查询运行得很快。我不认为它会检查数百万行 - 如果不幸的话,可能会检查几百行或几千行。一旦找到 10 个匹配行,它就可以停止而不检查更多行。
另一方面,如果您选择出现次数少于 10 次的标签,速度会很慢,因为它必须扫描该博客中的所有行。
您是否有性能测量结果表明,即使您正在搜索的标签经常出现,查询也特别慢?EXPLAIN您可以发布查询的输出吗?