【发布时间】:2021-02-20 07:27:16
【问题描述】:
我有两个 postgres 表
表 A
| id | owner_id |
|---|---|
| 1 | 100 |
| 2 | 101 |
表 B
| id | a_id | user_id |
|---|---|---|
| 1 | 1 | 200 |
| 2 | 1 | 201 |
| 3 | 2 | 202 |
| 4 | 2 | 201 |
两个表上的id 是PK 和integer
我在a.owner_id、b.a_id、b.user_id 上有B-Tree 索引
第一次查询
在下面的查询中
SELECT b.id
FROM b JOIN a ON b.a_id = a.id
WHERE b.user_id = 201
OR a.owner_id = 100
LIMIT 50;
我有WHERE b.user_id = 201 OR a.owner_id = 100 条件,查询计划使用b.user_id 的索引,但未使用a.owner_id 的索引,这是查询计划
QUERY PLAN
Limit (cost=19.54..4445.84 rows=50 width=4) (actual time=0.125..5.031 rows=50 loops=1)
Buffers: shared hit=1054
-> Merge Join (cost=19.54..9815083.22 rows=110872 width=4) (actual time=0.123..5.018 rows=50 loops=1)
Merge Cond: (a.id = b.a_id)
Join Filter: ((b.user_id = 201) OR (a.owner_id = 100))
Rows Removed by Join Filter: 5547
Buffers: shared hit=1054
-> Index Scan using a_pkey on a (cost=0.42..103568.63 rows=100009 width=20) (actual time=0.011..0.037 rows=50 loops=1)
Buffers: shared hit=10
-> Index Scan using b_a_id on b (cost=0.43..9515274.99 rows=11200116 width=24) (actual time=0.009..3.136 rows=5597 loops=1)
Buffers: shared hit=1044
Planning Time: 0.626 ms
Execution Time: 5.082 ms
查询有点慢,请问怎样才能更快?
第二次查询
还有另一个较慢的查询
SELECT b.id
FROM b JOIN a ON b.a_id = a.id
WHERE (b.user_id = 201 AND a.owner_id = 100)
OR (b.user_id = 100 AND a.owner_id = 201)
LIMIT 50;
QUERY PLAN
Limit (cost=1000.43..19742.38 rows=50 width=4) (actual time=0.705..63.142 rows=50 loops=1)
Buffers: shared hit=1419 read=3994
-> Gather (cost=1000.43..75593.36 rows=199 width=4) (actual time=0.704..63.124 rows=50 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=1419 read=3994
-> Nested Loop (cost=0.43..74573.46 rows=83 width=4) (actual time=0.752..13.122 rows=17 loops=3)
Buffers: shared hit=1419 read=3994
-> Parallel Seq Scan on a (cost=0.00..25628.06 rows=83 width=20) (actual time=0.669..11.868 rows=17 loops=3)
Filter: ((owner_id = 100) OR (owner_id = 201))
Rows Removed by Filter: 16985
Buffers: shared hit=258 read=3994
-> Index Scan using b_a_id on b (cost=0.43..589.69 rows=1 width=24) (actual time=0.023..0.070 rows=1 loops=52)
Index Cond: (a_id = a.id)
Filter: (((user_id = 201) OR (user_id = 100)) AND (((user_id = 201) AND (a.owner_id = 100)) OR ((a.owner_id = 201) AND (user_id = 100))))
Rows Removed by Filter: 105
Buffers: shared hit=1161
Planning Time: 0.638 ms
Execution Time: 63.202 ms
【问题讨论】:
-
该计划看起来很合理,但要进行更详细的分析,我们需要查看使用
explain (analyze, buffers, format text)生成的计划 - 而不仅仅是“简单”的解释跨度> -
@a_horse_with_no_name 我更新了查询计划
-
5 毫秒秒不符合“对我来说有点慢”的条件。你需要多快?
-
尝试将
OR条件改为UNION可能会更快 -
@a_horse_with_no_name 是的,5 毫秒并不慢,但是当我想用
OFFSET获取下一页时,它非常慢,需要>10 秒
标签: postgresql query-optimization