【发布时间】:2020-01-16 17:59:15
【问题描述】:
想象一下,我正在设计一个多用户博客,我有 user、post 和 comment 表,这些表具有明显的含义。在主页上,我想显示最近的十个帖子以及所有相关的 cmets。
天真的方法是SELECT 是最近的十个posts,可能是JOINed 和写它们的users。然后我可以通过它们循环到SELECT cmets,再次,可能是JOINed 与编写它们的用户。这需要 11 次选择:1 次用于帖子,10 次用于他们的 cmets,因此著名的反模式的名称是:n+1 次选择。
避免这种反模式的通常建议是使用第一个查询中的 ID 在第二个查询中获取所有相关的 cmets,如下所示:
SELECT
*
FROM
comments
WHERE
post_id IN (/* A comma separated list of post IDs returned from the first query */)
只要逗号分隔的列表相当短,我们就设法通过仅发出两个SELECT 查询而不是十一个查询来获取我们需要的所有数据。太好了。
但是,如果我只想要每个帖子的前三个 cmets 怎么办?我没有尝试,但我可能会想出一些 LEFT JOIN 诡计来在单个查询中获取最新帖子及其前三个 cmets,但我不确定它是否具有可扩展性。例如,如果我想要超过典型 MySQL 安装的 61 个表的连接限制的前 100 个 cmets,该怎么办?
除了恢复到 n+1 选择反模式之外,通常的解决方案是什么?在这种相当典型的场景中,使用与每个项目相关的项目子集来获取项目的最有效方法是什么?
【问题讨论】:
-
你的 rdbms 是什么? Sql Server、postgres、oracle?什么版本?
-
@JuanCarlosOropeza 我认为这在这里并不重要,因为这是一个理论问题,我最感兴趣的是通用解决方案。但也欢迎针对特定 RDBM 的解决方案。
标签: mysql sql join select greatest-n-per-group