我有两个Postgres表:'user'具有唯一的行,'address'中单个用户可以有多个地址。我想将特定的“用户”行与“地址”中的一行连接起来,其中address.id是最高的max(id)
。
我写了下面的查询,它工作正常,但我怀疑当一个用户有很多地址时,这个查询将在返回最终结果之前产生一个非常大的中间聚合。有没有更好的方法来编写这个查询?
select "user".id,
"user".username,
"user".trader_id,
address.id,
address.street,
address.trader_id
from "user", address
where "user".id = 6
and address.trader_id = "user".trader_id
order by address.id desc
limit 1;
字符串
4条答案
按热度按时间czfnxgou1#
您的查询对于获取单个用户来说已经很好了。绝对比在子查询中对整个
address
表运行窗口函数快得多。您的查询,仅使用
USING
子句稍微简化:字符串
address(trader_id, id)
上的多列索引将为您提供最佳性能。另外,很明显,还有一个"user"(id)
的索引。(没有像你用LIMIT 1
逮捕的“中间聚合”!)参见:或者,在
LATERAL
子查询中使用相同的技术。用于检索一个或多个用户:型
关于
LATERAL
子查询:还使用
LEFT JOIN
来保存没有任何地址的用户。如果要使用窗口函数,请使用
row_number()
而不是rank()
。在LATERAL
子查询中执行此操作,同时只检索单个(或少数)用户,以便只涉及相关行。而且,除非你运行Postgres 16或更高版本,否则添加frame子句ROWS UNBOUNDED PRECEDING
以提高性能:型
为什么是
ROWS UNBOUNDED PRECEDING
?请参阅:或者使用
DISTINCT ON
:型
请参阅:
__
旁白:不要像“user”那样使用reserved words作为标识符。
2ekbmq322#
您的查询应该工作得很好并且性能良好,特别是如果您使用了适当的索引,例如对于两个表都使用了
trader_id
索引。(可以进行某些改进,例如删除第二个trader_id
列,并为一个或两个id
列使用别名。但是,如果您想获取多个用户的信息,查询将失败,因为
LIMIT 1
子句只返回一行。那么,一个更通用的解决方案,你可以一次获得多个"user".id
的所需信息,将使用窗口函数:字符串
在性能方面,您应该关注索引而不是查询结构-查询计划器将处理后者。
kd3sttzy3#
您可以跳过在查询中使用order by和limit,使用多列子查询从所有/任何用户的地址表中获取最大id。
步骤1:从地址表中写入所有用户获取最大地址ID。
字符串
步骤2:将上述查询放入另一个查询中,以获取地址表中所需的列。
型
步骤3:将上述查询与“user”表连接。你可以使用where条件从这里获取任何用户的最新地址id。
型
um6iljoc4#
为了探索性能问题,创建一个能够暴露差异的测试床是很有用的。以下命令建立一个具有足够行数的环境,以演示不同查询的相对性能(调整
p
中的参数以模拟不同的数据特征):字符串
下面列出了几个查询,每个查询都返回OP所需的结果,沿着在我的笔记本电脑上运行时的平均完成时间。
正如Erwin Brandstetter所指出的,当查询一个用户时,下面的子查询的性能很差,因为子查询必须处理所有的
addresses
,即使只有与单个交易者相关的那些是感兴趣的。在查询所有用户时,此查询的性能优于其他查询。型
3923.033 ms(所有用户为3654.100 ms)
当查询单个用户时,下一个版本的查询的性能明显优于前一个版本;但是,它在查询所有用户时的性能明显更差。
型
0.361 ms(所有用户为5072.365 ms)
第三个版本的性能在统计上与前一个版本的单用户查询性能相同,在查询所有用户时仅比第一个版本稍差。
型
0.356 ms(所有用户为3963.354 ms)
通过对
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
的输出进行更深入的分析,可以获得更多的insite。