PostgreSQL查询性能调优

EXPLAIN

explain输出执行计划而不是执行SQL语句本身,加上analyze实参之后的执行效果是执行该SQL语句本身且会将实际执行情况与执行计划进行对比分析,这可以用来评估执行计划的准确性。
-- verbose 参数使得输出执行计划精确到列级别
-- explain(analyze,buffers) 显示出执行计划过程重用缓存数据时的命中次数。缓存中已有的数据块就不要从磁盘读取了

输出内容解释

explain(analyze)select tract_id,hispanic_or_latino from census.hisp_pop where tract_id='20240227'
输出结果:
Seq Scan on hisp_pop
(cost=0.00..33.48 rows=1 width=16)
(actual time=0.205..0.339 rows=1 loops=1)
Filter:((tract_id)::text='20240227'::text)
Rows Removed by Filter: 1477
Total runtime:0.360 ms
Planning time: 0.095 ms
Execution time: 0.381 ms

结果解析:
cost=0.00..33.48
数字0.00 是估算的该步骤起始执行时间(起步时间,如果有索引,起步时间不是0,因为规划器需要扫描索引先),第二个数字33.48是估算的该步骤总执行时间,这个是估算的执行时间并不是真实的时间单位,而是取决于硬件环境以及规划器的执行时间单位常数(seq_page_cost 和 cpu_tuple_cost)

Rows Removed by Fileter 1477 是扫描过程中排除掉的不符合条件的记录数
执行分析时间就是规划器分析出最终执行计划所消耗的时间;
执行时间是按照执行计划并得到最终结果所用的时间。

搜集语句的执行统计信息

性能调优的第一步就是要确定哪些语句是性能瓶颈。利用扩展包pg_stat_statements的性能监控扩展包以帮助用户找出耗时最长的语句。
启动时指定预加载动态库
1 在postgresql.conf配置文件中,将 shared_preload_libraries='pg_stat_statements'
2 pg_stat_statements.max=10000
pg_stat_statements.track=all
3 重启postgresql
4 在数据库中执行: create extension pg_stat_statements;

找出book库中最耗时间5个SQL语句
select query,calls,total_time,rows,100.0 * shared_blks_hit/nullif(shared_blks_hit + shared_blks_read,0) AS hit_percent from pg_stat_statements As s Inner Join pg_database As d On d.oid = s.dbid where d.datname='postgresql_book' order by total_time desc limit 5;

索引有没有用到

通过查询pg_stat_user_indexes和pg_stat_user_tables 这两个视图可以很方便的得知你的索引是否被用上了,这两个视图由pg_stat_statements扩展包提供。

set enable_seqscan =true;//启动全表扫描策略
explain(analyze)
select * from census.lu_fact_types where fact_subcats && '{White alone,Black alone}'::varchar[];

结果:
seq scan on lu_fact_types
(cost=0.00..2.85 rows=2 width=200) (actual time=0.066..0.076 rows=2 loops=1)
Filter: (fact_subcats && '{"White alone","Black alone"}'::character varying[]) Rows Removed by Filter: 66
Planning time: 0.182ms
Execution time: 0.108ms
规划器忽略了索引选用了全表扫描策略。可能是表太小,或者因为索引不适用本语句的查询条件。

set enable_seqscan =false;//禁用全表扫描策略
explain(analyze)
select * from census.lu_fact_types where fact_subcats && '{White alone,Black alone}'::varchar[];

Bitmap Heap Scan on lu_fact_types
(cost=12.02..14.04 rows=2 width=200) (actual time=0.058..0.058 rows=2 loops=1) Recheck Cond: (fact_subcats && '{"White alone","Black alone"}'::character varying[]) Heap Blocks: exact=1 -> Bitmap Index Scan on idx_lu_fact_types (cost=0.00..12.02 rows=2 width=0) (actual time=0.048..0.048 rows=2 loops=1) Index Cond: (fact_subcats && '{"White alone","Black alone"}'::character varying[] )
Planning time : 0.230ms
Execution time: 0.119ms

表的统计信息

pg_stats 表给出了表中指定列的值域分布图,规划器会根据此信息制定相应的执行计划。系统后台会有一个进程持续不断的更新pg_stats表。
当表插入或者删除大量数据之后,用vacuum analyze 来更新表的统计信息;
vacuum 将已删除的记录永久性的从表中移除,analyze指示更新表的统计信息。

磁盘页随机访问成本

random_page_cost RPC 随机也访问成本比,表示磁盘上顺序读取和随机读取同一条记录的性能直逼。一般物理磁盘速度越快,该比率就会越小,RPC默认是4
alter tablespace pg_default set (random_page_cost=2);

避免使用 select * 语法

缺点:导致性能浪费,网络传输负担加大
与大对象有关,pgsq 用toast(大尺寸属性存储技术)来存储二进制大对象以及超大文本,将超过主表存储限制的数据存储到一张辅助表,因此读取超大字段就是多表关联操作。
与视图有关,视图创建时可能有若干不要的列,系统会自动将星号替换为目的表的完整字段列表,访问时,所有复杂咧都会参与运算,查询速度回很慢。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注