Postgres:如何在 Have 子句中进行 NULL 友好的 MIN 过滤以准确选择一行?

Posted

技术标签:

【中文标题】Postgres:如何在 Have 子句中进行 NULL 友好的 MIN 过滤以准确选择一行?【英文标题】:Postgres: How to make NULL friendly MIN filtering in Having clause to select exactly one row? 【发布时间】:2021-10-07 19:37:40 【问题描述】:

根据 Gordon Linoff 的建议,我为 Postgres: How to make NULL friendly MIN filtering in Having clause? 创建了一个新的后续问题

SELECT userId FROM audit_table
GROUP BY userId 
HAVING MIN(updatedDate) > ? OR MIN(updatedDate) IS NULL;
ORDER BY userId 
LIMIT 1

有没有办法让这个查询在 POSTGRES 中更高效?

【问题讨论】:

您可以在帖子中添加索引和explain analyse 吗? @Jim Jones 我有更新日期的索引 哪个索引?请添加查询计划。 OR 转换为UNION;按更新日期索引;限制每个子查询并限制 UNION。 您有单独的用户表吗? audit_table 有多大?有哪些索引可用? 【参考方案1】:

如果您担心性能,您可以:

将 OR 转换为 UNION ALL。 索引updatedDate。 限制每个子查询,并且 限制 UNION ALL。

例如你可以添加索引(和一些数据):

create table audit_table (
  userId int,
  updatedDate date
);

insert into audit_table (userId, updatedDate) values
  (123, '2021-02-03'),
  (456, '2021-04-12'),
  (789, '2021-01-22'),
  (477, null);

create index ix1 on audit_table (updatedDate nulls last, userId);

那么查询将使用索引:

select *
from (
  (
  select userId, updatedDate
  from audit_table
  order by updatedDate nulls last
  limit 1
  )
 union all
  (
  select userId, updatedDate
  from audit_table
  where updatedDate is null
  limit 1
  )
) x
order by updatedDate nulls last
limit 1

结果:

 userid  updateddate
 ------- -----------
 789     2021-01-22

当有大量行时,上面的查询将使用索引。如果表只有几百行,引擎可能最终会忽略索引,而是读取整个表。

注意:如果同时找到空行和非空行,您可以选择优先考虑哪一行。在上一行到最后一行中,nulls first 将优先考虑空行,而nulls last 将优先考虑非空行。

请参阅DB Fiddle 的运行示例。

【讨论】:

以上是关于Postgres:如何在 Have 子句中进行 NULL 友好的 MIN 过滤以准确选择一行?的主要内容,如果未能解决你的问题,请参考以下文章

SQL - 如何在have子句中对结果进行分组和筛选后,如何汇总列?

如何在 Hive/SQL 的 where/have 子句中使用 min()(以避免子查询)

如何在sqlite django ORM中实现have子句

关系代数中 GroupBy 和 Have 子句的等价物

使用具有不同 order by 子句的 postgres 窗口函数

FROM 子句中的 Postgres 子查询