如何在 postgres 中有效地(使用索引)查找未引用的行?

How to find unreferenced rows efficiently (with an index) in postgres?

如何在 postgresql 中有效地找到没有指向它们的外键的巨大 table 行?

假设我们有一个 table 的橙子和橙子分析结果。橙色主键不受我们控制,也没有任何特定顺序。橙子具有与专用程序进行的分析相关的列。

Table oranges(PK超过orange_id,btree超过created_at):

orange_id | raw_orange_data | created_at
1         | '{ "foo": 5}'   | '2021-08-09 15:00:00'
4092141   | '{ "foo": 42}'  | '2021-08-09 16:00:00'
42        | '{ "foo": 13}'  | '2021-08-09 11:00:00'

上述其他程序存在多个版本,我们希望保留结果以供比较。我们应该如何安排外键才能select下一个需要高效处理的橘子?

Table orange_analysis (PK over orange_id, analysis_version):

orange_id | analysis_version| analysis_result
1         | 1               | 9000
1         | 2               | 9001
4092141   | 1               | 50
4092141   | 2               | 60

我们目前正在考虑

SELECT *
FROM oranges
LEFT JOIN orange_analysis ON oranges.id = orange_analysis.orange_id
WHERE (oranges_analysis.orange_id IS NULL AND oranges_analysis.analysis_version = 1)
ORDER BY oranges.created_at DESC
LIMIT 500

NOT EXISTS 查询,但我担心他们无法使用索引。

有没有办法组织我们的 table 以确保此类查询 运行 快速?没有 postgres 走过 oranges table 可以完成吗?如果我们没有多个版本,我会使用可为空的 FK 到 orange_analysis,但不幸的是,我们必须维护多个分析版本。

我想出的唯一一件事是让 analysis_result 可以为空,为所有分析变体的所有橙子创建它为空,在其上放置一个索引,并将 analysis_result 列设置为一旦分析取得进展,它各自的价值。

如果您正在寻找缺少特定版本的橙子,那么您可以使用:

SELECT o.*
FROM oranges o LEFT JOIN
     orange_analysis oa
     ON o.id = oa.orange_id AND oa.analysis_version = 1
WHERE oa.orange_id IS NULL 
ORDER BY o.created_at DESC
LIMIT 500;

不过,为了性能,我可能会建议 NOT EXISTS 使用特定索引:

SELECT o.*
FROM oranges o 
WHERE NOT EXISTS (SELECT 1
                  FROM orange_analysis oa
                  WHERE o.id = oa.orange_id AND oa.analysis_version = 1
                 )
ORDER BY o.created_at DESC
LIMIT 500;

您需要的索引是 oranges(created_at desc, id)orange_analysis(orange_id, analysis_version)。这些也适用于 LEFT JOIN 版本,但我不确定它们是否会避免对 ORDER BY.

进行排序

我认为普通集合操作通常是最有效的方法:

SELECT id FROM oranges
EXCEPT
SELECT orange_id FROM orange_analysis
   WHERE analysis_version = 1;

这将仅输出第一个查询中没有出现在第二个查询结果中的那些行(设置差异)。