极慢 "row_number() over order" 查询
Extremely slow "row_number() over order" query
我有一个用户 table 有列(id、xp、...)和大约 150 万行。
我通过以下查询(执行时间为 33 秒)获得某人在 XP 排行榜中的位置:
EXPLAIN ANALYZE WITH counts AS (
SELECT DISTINCT
id,
ROW_NUMBER () OVER (ORDER BY xp DESC)
FROM
users
) SELECT
*
FROM
counts
WHERE
id=1;
Subquery Scan on counts (cost=344492.80..395160.57 rows=7404 width=16) (actual time=30683.244..32174.117 rows=1 loops=1)
Filter: (counts.id = '1'::bigint)
Rows Removed by Filter: 1481060
-> HashAggregate (cost=344492.80..376651.79 rows=1480702 width=24) (actual time=30679.440..32034.921 rows=1481061 loops=1)
Group Key: users.id, row_number() OVER (?)"
Planned Partitions: 64 Batches: 65 Memory Usage: 4369kB Disk Usage: 125960kB
-> WindowAgg (cost=212155.06..238067.34 rows=1480702 width=24) (actual time=2983.137..20302.548 rows=1481061 loops=1)
-> Sort (cost=212155.06..215856.81 rows=1480702 width=16) (actual time=2983.082..5040.782 rows=1481061 loops=1)
Sort Key: users.xp DESC
Sort Method: external merge Disk: 37760kB
-> Seq Scan on users (cost=0.00..35094.02 rows=1480702 width=16) (actual time=25.467..880.626 rows=1481061 loops=1)
Planning Time: 2.593 ms
JIT:
Functions: 14
Options: Inlining false, Optimization false, Expressions true, Deforming true"
Timing: Generation 12.061 ms, Inlining 0.000 ms, Optimization 1.503 ms, Emission 26.086 ms, Total 39.650 ms"
Execution Time: 32325.206 ms
我的table定义:
CREATE TABLE users
(
id bigint NOT NULL
CONSTRAINT users_pkey
PRIMARY KEY,
xp bigint DEFAULT 0 NOT NULL,
...
);
CREATE INDEX user_xp_leaderboard_index
ON users (xp DESC, id ASC);
但是速度极慢。虽然考虑到它对整个 table 进行排序并对其进行过滤并不奇怪,但我不知道如何 improve/optimize 这个查询。
我做到了SET work_mem TO '1 GB';
。有点帮助,但帮助不大。
如有任何帮助,我们将不胜感激。提前致谢。
您可以这样写查询:
select count(*)
from users u
where u.xp >= (select u2.xp from users u2 where u2.id = 1);
这可以利用 users(id, xp)
上的索引。这应该完全消除任何排序。如果行很宽并且 Postgres 可以使用仅索引扫描,users(xp)
上的索引也可能有帮助。
我有一个用户 table 有列(id、xp、...)和大约 150 万行。
我通过以下查询(执行时间为 33 秒)获得某人在 XP 排行榜中的位置:
EXPLAIN ANALYZE WITH counts AS (
SELECT DISTINCT
id,
ROW_NUMBER () OVER (ORDER BY xp DESC)
FROM
users
) SELECT
*
FROM
counts
WHERE
id=1;
Subquery Scan on counts (cost=344492.80..395160.57 rows=7404 width=16) (actual time=30683.244..32174.117 rows=1 loops=1)
Filter: (counts.id = '1'::bigint)
Rows Removed by Filter: 1481060
-> HashAggregate (cost=344492.80..376651.79 rows=1480702 width=24) (actual time=30679.440..32034.921 rows=1481061 loops=1)
Group Key: users.id, row_number() OVER (?)"
Planned Partitions: 64 Batches: 65 Memory Usage: 4369kB Disk Usage: 125960kB
-> WindowAgg (cost=212155.06..238067.34 rows=1480702 width=24) (actual time=2983.137..20302.548 rows=1481061 loops=1)
-> Sort (cost=212155.06..215856.81 rows=1480702 width=16) (actual time=2983.082..5040.782 rows=1481061 loops=1)
Sort Key: users.xp DESC
Sort Method: external merge Disk: 37760kB
-> Seq Scan on users (cost=0.00..35094.02 rows=1480702 width=16) (actual time=25.467..880.626 rows=1481061 loops=1)
Planning Time: 2.593 ms
JIT:
Functions: 14
Options: Inlining false, Optimization false, Expressions true, Deforming true"
Timing: Generation 12.061 ms, Inlining 0.000 ms, Optimization 1.503 ms, Emission 26.086 ms, Total 39.650 ms"
Execution Time: 32325.206 ms
我的table定义:
CREATE TABLE users
(
id bigint NOT NULL
CONSTRAINT users_pkey
PRIMARY KEY,
xp bigint DEFAULT 0 NOT NULL,
...
);
CREATE INDEX user_xp_leaderboard_index
ON users (xp DESC, id ASC);
但是速度极慢。虽然考虑到它对整个 table 进行排序并对其进行过滤并不奇怪,但我不知道如何 improve/optimize 这个查询。
我做到了SET work_mem TO '1 GB';
。有点帮助,但帮助不大。
如有任何帮助,我们将不胜感激。提前致谢。
您可以这样写查询:
select count(*)
from users u
where u.xp >= (select u2.xp from users u2 where u2.id = 1);
这可以利用 users(id, xp)
上的索引。这应该完全消除任何排序。如果行很宽并且 Postgres 可以使用仅索引扫描,users(xp)
上的索引也可能有帮助。