当该信息存储在辅助 table 中时,如何查询 SQL 中页面的最新版本?
How can I query the latest version of a page in SQL, when that information is stored in a secondary table?
假设我正在编写一个 wiki¹。我可能有一个 table 包含每个 wiki 页面的一行,另一个包含该页面的每个版本,以及该版本对应的页面的外键。用户可能会请求查看每个页面的列表,包括页面标题(包含在版本中 table 因为标题可以更新,因此应该使用版本进行跟踪)。
我可以先做一个查询来获取维基页面列表,然后再做一个单独的查询来获取每个页面的标题,但是这个查询数量似乎运行的查询比我需要的要多得多,而且由于服务器往返以及 SQL 库中的一些(非常小的)阻塞,因此性能较低。
相反,我宁愿在 wiki 页面 table 和版本 table 之间做一些类似 JOIN 的事情,但是这样我会在每个版本的结果中得到一个单独的行,传输和准备比我需要的更多的数据。在我查看页面内容的查询中,我只使用 ORDER BY timestamp DESC LIMIT 1
,它在那里非常有效地解决了这个问题,但是这对列表情况不起作用 as-is,因为我需要不止一行。我可以将顺序和限制分别应用于共享页面 ID 的每组行吗?
我的下一个想法是尝试使用子查询,这就是我的研究尝试所指向的全部内容,基本上是我的第一个选项,但 Postgres 的优化器可以立即看到整个操作并希望对其进行更多优化与许多查询相比,为了避免更多的往返和阻塞,但是当我查看 Postgres 时 list of available subquery options,我无法弄清楚如何使用它们中的任何一个来解决这个问题。
最后,我可以将标题(以及我在此查询中需要的其他 per-version 数据)存储在主 table 中,但这是数据重复,因此是一种不好的做法。尽管如此,这似乎是我目前能想到的最不邪恶的;因此,问题是:如何查询我需要的数据,以高性能方式生成包含最新 per-version 数据且不重复数据的 wiki 页面列表?
1: 我的项目不是 wiki,但由于它的详细信息目前是私有的,所以我需要举一个稍微做作的例子。
您描述的是每组前 1 名的问题。在没有看到实际结构的情况下,这是相当理论化的,但是可以在 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
假设我正在编写一个 wiki¹。我可能有一个 table 包含每个 wiki 页面的一行,另一个包含该页面的每个版本,以及该版本对应的页面的外键。用户可能会请求查看每个页面的列表,包括页面标题(包含在版本中 table 因为标题可以更新,因此应该使用版本进行跟踪)。
我可以先做一个查询来获取维基页面列表,然后再做一个单独的查询来获取每个页面的标题,但是这个查询数量似乎运行的查询比我需要的要多得多,而且由于服务器往返以及 SQL 库中的一些(非常小的)阻塞,因此性能较低。
相反,我宁愿在 wiki 页面 table 和版本 table 之间做一些类似 JOIN 的事情,但是这样我会在每个版本的结果中得到一个单独的行,传输和准备比我需要的更多的数据。在我查看页面内容的查询中,我只使用 ORDER BY timestamp DESC LIMIT 1
,它在那里非常有效地解决了这个问题,但是这对列表情况不起作用 as-is,因为我需要不止一行。我可以将顺序和限制分别应用于共享页面 ID 的每组行吗?
我的下一个想法是尝试使用子查询,这就是我的研究尝试所指向的全部内容,基本上是我的第一个选项,但 Postgres 的优化器可以立即看到整个操作并希望对其进行更多优化与许多查询相比,为了避免更多的往返和阻塞,但是当我查看 Postgres 时 list of available subquery options,我无法弄清楚如何使用它们中的任何一个来解决这个问题。
最后,我可以将标题(以及我在此查询中需要的其他 per-version 数据)存储在主 table 中,但这是数据重复,因此是一种不好的做法。尽管如此,这似乎是我目前能想到的最不邪恶的;因此,问题是:如何查询我需要的数据,以高性能方式生成包含最新 per-version 数据且不重复数据的 wiki 页面列表?
1: 我的项目不是 wiki,但由于它的详细信息目前是私有的,所以我需要举一个稍微做作的例子。
您描述的是每组前 1 名的问题。在没有看到实际结构的情况下,这是相当理论化的,但是可以在 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