获取具有最高价值的顶行,有联系
Get top row(s) with highest value, with ties
我在 PostgreSQL 中有一个名为 product
的关系,它包含 2 个字段:id
和 quantity
。
我想找到 id
最高 quantity
的产品。据我所知,有两种方法可以做到:
SELECT id FROM product WHERE quantity >= ALL(SELECT quantity FROM product)
或
SELECT id FROM product WHERE quantity = (SELECT MAX(quantity) FROM product)
他们的执行速度有什么不同吗?
我在 postgres 中尝试了您的方法(测试 table 由 id 分发)。第一种方法 运行 对我来说要慢得多。这是我的比较结果:
上述方法一:3.1秒
上面方法2:0.13秒
方法一在反复的努力中至少慢了10倍。我认为您的方法 2 是更好的选择,因为子查询的运行速度可能比其他选项中的子查询快得多。
您的查询不等同。如果 quantity
值中的 any 是 NULL
,则第一个 returns 根本没有行。第二个忽略 NULL
值。
Here 是一个 db<>fiddle 说明这一点。
有第三种变体
SELECT id FROM product
WHERE quantity = (SELECT quantity FROM product ORDER BY quantity DESC NULLS LAST LIMIT 1)
如果 table 的 btree 索引为(数量 DESC NULLS LAST),此变体将非常快
如果任何行有 quantity IS NULL
(如 ),则第一个查询失败。
仅当所有行都具有 quantity IS NULL
时,第二个查询才会失败。所以它应该在大多数情况下可用。 (而且速度更快。)
Postgres 13 或更新版本
使用标准 SQL 子句 WITH TIES
:
SELECT id
FROM product
ORDER BY quantity DESC NULLS LAST
FETCH FIRST 1 ROWS WITH TIES;
db<>fiddle here
适用于任意数量的 NULL
个值。
SQL:2008 introduced a different syntax to achieve the same result,
which PostgreSQL also supports. It is:
OFFSET start { ROW | ROWS }
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }
In this syntax, the start
or count
value is required by the standard
to be a literal constant, a parameter, or a variable name; as a
PostgreSQL extension, other expressions are allowed, but will
generally need to be enclosed in parentheses to avoid ambiguity. If
count
is omitted in a FETCH
clause, it defaults to 1. The WITH TIES
option is used to return any additional rows that tie for the last
place in the result set according to the ORDER BY
clause; ORDER BY
is
mandatory in this case. ROW
and ROWS
as well as FIRST
and NEXT
are
noise words that don't influence the effects of these clauses.
值得注意的是,WITH TIES
不能与(非标准)短语法 LIMIT n
.
一起使用
这是可能最快的解决方案。比您当前的任何一个查询都快。对于 性能 更重要:在 (quantity)
上有一个 index。或者更专业的覆盖索引以允许仅索引扫描(更快一点):
CREATE INDEX ON product (quantity DESC NULLS LAST) INCLUDE (id);
参见:
我们需要 NULLS LAST
来保持 NULL
值按降序排列在最后。参见:
- Sort by column ASC, but NULL values first?
Postgres 12 或更早版本
NULL 安全查询:
SELECT id, quantity
FROM product
WHERE quantity IS NOT DISTINCT FROM (SELECT MAX(quantity) FROM product);
或者,可能更快:
SELECT id, quantity
FROM (
SELECT *, rank() OVER (ORDER BY quantity DESC NULLS LAST) AS rnk
FROM product
) sub
WHERE rnk = 1;
参见:
- PostgreSQL equivalent for TOP n WITH TIES: LIMIT "with ties"?
大表的更快替代品:
我在 PostgreSQL 中有一个名为 product
的关系,它包含 2 个字段:id
和 quantity
。
我想找到 id
最高 quantity
的产品。据我所知,有两种方法可以做到:
SELECT id FROM product WHERE quantity >= ALL(SELECT quantity FROM product)
或
SELECT id FROM product WHERE quantity = (SELECT MAX(quantity) FROM product)
他们的执行速度有什么不同吗?
我在 postgres 中尝试了您的方法(测试 table 由 id 分发)。第一种方法 运行 对我来说要慢得多。这是我的比较结果:
上述方法一:3.1秒
上面方法2:0.13秒
方法一在反复的努力中至少慢了10倍。我认为您的方法 2 是更好的选择,因为子查询的运行速度可能比其他选项中的子查询快得多。
您的查询不等同。如果 quantity
值中的 any 是 NULL
,则第一个 returns 根本没有行。第二个忽略 NULL
值。
Here 是一个 db<>fiddle 说明这一点。
有第三种变体
SELECT id FROM product
WHERE quantity = (SELECT quantity FROM product ORDER BY quantity DESC NULLS LAST LIMIT 1)
如果 table 的 btree 索引为(数量 DESC NULLS LAST),此变体将非常快
如果任何行有 quantity IS NULL
(如
仅当所有行都具有 quantity IS NULL
时,第二个查询才会失败。所以它应该在大多数情况下可用。 (而且速度更快。)
Postgres 13 或更新版本
使用标准 SQL 子句 WITH TIES
:
SELECT id
FROM product
ORDER BY quantity DESC NULLS LAST
FETCH FIRST 1 ROWS WITH TIES;
db<>fiddle here
适用于任意数量的 NULL
个值。
SQL:2008 introduced a different syntax to achieve the same result, which PostgreSQL also supports. It is:
OFFSET start { ROW | ROWS } FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }
In this syntax, the
start
orcount
value is required by the standard to be a literal constant, a parameter, or a variable name; as a PostgreSQL extension, other expressions are allowed, but will generally need to be enclosed in parentheses to avoid ambiguity. Ifcount
is omitted in aFETCH
clause, it defaults to 1. TheWITH TIES
option is used to return any additional rows that tie for the last place in the result set according to theORDER BY
clause;ORDER BY
is mandatory in this case.ROW
andROWS
as well asFIRST
andNEXT
are noise words that don't influence the effects of these clauses.
值得注意的是,WITH TIES
不能与(非标准)短语法 LIMIT n
.
这是可能最快的解决方案。比您当前的任何一个查询都快。对于 性能 更重要:在 (quantity)
上有一个 index。或者更专业的覆盖索引以允许仅索引扫描(更快一点):
CREATE INDEX ON product (quantity DESC NULLS LAST) INCLUDE (id);
参见:
我们需要 NULLS LAST
来保持 NULL
值按降序排列在最后。参见:
- Sort by column ASC, but NULL values first?
Postgres 12 或更早版本
NULL 安全查询:
SELECT id, quantity
FROM product
WHERE quantity IS NOT DISTINCT FROM (SELECT MAX(quantity) FROM product);
或者,可能更快:
SELECT id, quantity
FROM (
SELECT *, rank() OVER (ORDER BY quantity DESC NULLS LAST) AS rnk
FROM product
) sub
WHERE rnk = 1;
参见:
- PostgreSQL equivalent for TOP n WITH TIES: LIMIT "with ties"?
大表的更快替代品: