Aru*_*run 5 postgresql postgresql-performance
我正在运行一个查询,例如
select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d';
Run Code Online (Sandbox Code Playgroud)
在桌子上看起来像
Table "public.students"
Column | Type | Modifiers
-------------------+-----------------------------+------------------------------------
id | uuid | not null default gen_random_uuid()
school_id | uuid |
Indexes:
"students_pkey" PRIMARY KEY, btree (id)
"students_school_id_idx" btree (school_id)
Run Code Online (Sandbox Code Playgroud)
select 语句的查询计划与 where 类似,如下所示:
explain select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d';
QUERY PLAN
--------------------------------------------------------------------------------------------------
Bitmap Heap Scan on students (cost=581.83..83357.10 rows=24954 width=16)
Recheck Cond: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
-> Bitmap Index Scan on students_school_id_idx (cost=0.00..575.59 rows=24954 width=0)
Index Cond: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
Run Code Online (Sandbox Code Playgroud)
这相当快。
现在我们将 order by 添加到带有 id 的查询中,这会降低查询的性能。(这样的查询是由 Rails 生成的,例如有一些条件的 Student.first)
explain select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d' order by id asc limit 1;
QUERY PLAN
------------------------------------------------------------------------------------------------------------
Limit (cost=0.43..488.51 rows=1 width=16)
-> Index Scan using students_pkey on students (cost=0.43..12179370.22 rows=24954 width=16)
Filter: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
Run Code Online (Sandbox Code Playgroud)
如何提高查询结果的返回速度?目前表中约有 4990731 条记录,耗时超过 2 分钟!它在带有 db.t2.medium 实例的 RDS 上运行。
运行后更新Analyze students;
explain select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d' order by id asc limit 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Limit (cost=8.46..8.46 rows=1 width=16)
-> Sort (cost=8.46..8.46 rows=1 width=16)
Sort Key: id
-> Index Scan using students_school_id_idx on students (cost=0.43..8.45 rows=1 width=16)
Index Cond: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
explain analyze select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d' order by id asc limit 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=8.46..8.46 rows=1 width=16) (actual time=1.853..1.855 rows=1 loops=1)
-> Sort (cost=8.46..8.46 rows=1 width=16) (actual time=1.851..1.852 rows=1 loops=1)
Sort Key: id
Sort Method: quicksort Memory: 25kB
-> Index Scan using students_school_id_idx on students (cost=0.43..8.45 rows=1 width=16) (actual time=1.841..1.843 rows=1 loops=1)
Index Cond: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
Planning time: 0.145 ms
Execution time: 1.874 ms
Run Code Online (Sandbox Code Playgroud)
ORDER BYPostgreSQL 认为,通过按排序顺序扫描行并丢弃行,直到找到具有正确 的行,可以更快地避免 的排序school_id。
这可能比预期花费的时间更长有两个原因:
表统计信息已关闭,并且 PostgreSQL 高估了该 的行数school_id。
计算新的统计数据,可能具有更高的 值default_statistics_target,以验证这是否是问题所在:
ANALYZE students;
Run Code Online (Sandbox Code Playgroud)具有正确值的(许多)行都school_id恰好具有相当高的id,因此 PostgreSQL 必须扫描比预期更多的行,直到找到匹配项。
在这种情况下,您应该修改该ORDER BY子句,以便 PostgreSQL 不能使用错误的索引:
... ORDER BY id + 0
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
2965 次 |
| 最近记录: |