当信息存储在辅助表中时,如何在 SQL 中查询页面的最新版本?

Posted

技术标签:

【中文标题】当信息存储在辅助表中时,如何在 SQL 中查询页面的最新版本?【英文标题】:How can I query the latest version of a page in SQL, when that information is stored in a secondary table? 【发布时间】:2021-03-26 15:39:12 【问题描述】:

假设我正在编写一个 wiki¹。我可能有一个表,其中包含每个 wiki 页面的一行,另一个表包含该页面的每个版本,以及版本对应的页面的外键。用户可以请求查看每个页面的列表,包括页面的标题(由于标题可以更新,因此应使用版本进行跟踪,因此该标题包含在版本表中)。

我可以先进行查询以获取 wiki 页面列表,然后进行单独查询以获取每个页面的标题,但这个查询数量似乎比我需要的查询多得多,因此由于服务器往返,以及 SQL 库中的一些(非常轻微的)阻塞,性能较低。

相反,我宁愿在 wiki 页面表和版本表之间执行类似 JOIN 的操作,但随后我会在结果中为每个版本获得单独的一行,传输和准备比我需要的更多的数据。在我查看页面内容的查询中,我只使用了ORDER BY timestamp DESC LIMIT 1,它可以很好地解决这个问题,但是这对于列表案例来说是行不通的,因为我需要不止一行。我可以将 order by 和 limit 分别应用于共享页面 id 的每组行吗?

我的下一个想法是尝试使用子查询,这就是我的研究尝试指向的全部内容,基本上是做我的第一个选择,但 Postgres 的优化器可以一次看到整个操作,并希望优化它而不是使用很多查询,为了避免更多的往返和阻塞,但是当我查看 Postgres 的 list of available subquery options 时,我无法弄清楚如何使用它们中的任何一个来解决这个问题。

最后,我可以将标题(以及我在此查询中需要的其他每个版本的数据)存储在主表中,但这是数据重复,因此是一种不好的做法。尽管如此,这似乎是我目前能想到的最不邪恶的事情。因此,问题是:如何查询我需要的数据,以高性能的方式生成包含最新每个版本数据的 wiki 页面列表,并且不重复数据?

1:我的项目不是一个wiki,但由于它的细节暂时是私人的,我需要举一个稍微做作的例子。

【问题讨论】:

【参考方案1】:

您正在描述一个 top-1-per-group 问题。在没有看到实际结构的情况下,这是相当理论上的,但可以在 Postgres 中使用distinct on 来实现逻辑。看起来像这样:

select distinct on (p.page_id) p.*, pv.title
from pages p
inner join page_versions pv on pv.page_id = p.page_id
order by p.page_id, pv.timestamp desc

或者您可以使用横向连接:

select p.*, pv.title
from pages p
cross join lateral (
    select pv.*
    from page_versions pv
    where pv.page_id = p.page_id
    order by pv.timestamp desc limit 1
) pv

【讨论】:

以上是关于当信息存储在辅助表中时,如何在 SQL 中查询页面的最新版本?的主要内容,如果未能解决你的问题,请参考以下文章

当日期不在table1中时,SQL查询In/Out考勤与空行

如何向本地存储帐户中的表编写 LINQ 查询?

当数据在 SQL Server 中时,如何通过 ADO 在 Access 中创建报表?

将sql查询存储在列表中时PHP内存耗尽

数据存储在对象存储中时从 Spark SQL 访问 Hive 表

仅当应用程序处于前台而不是通知中时,如何捕获辅助功能事件?