当前位置: 首页 > news >正文

HGDB索引膨胀的检查与处理思路

文章目录

  • 环境
  • 文档用途
  • 详细信息

环境

系统平台:Linux x86-64 Red Hat Enterprise Linux 7
版本:4.5.8

文档用途

本文档主要介绍HGDB索引膨胀的定义、产生的原因、如何检查以及遇到索引膨胀如何处理(包括预防和解决)

详细信息

索引膨胀的定义

假设对一个索引进行顺序的数据插入,那么索引分裂应该只会发生在最右边的叶子结点;若对索引进行无序的插入,那么中间的叶子结点会进行了分裂,多出了很多空闲空间,索引扫描的时候需要扫描更多的页,造成了io和存储空间上的浪费

产生膨胀索引的原因

1、表中的每个行版本(“元组”)都有一个未死亡的索引条目。当 VACUUM 删除死元组时,它还必须删除相应的索引条目,这会在索引页中创建空白空间。此类空间可以重复使用,但如果没有新条目添加到页面,则该空间仍为空

2、频繁更新相同的行,在VACUUM清理老元组前,表和索引会维护相同行的很多版本。若索引页填满,HGDB会将索引页分裂成2个,在VACUUM执行完清理之后,最终会得到2个臃肿的页面而不是1个

索引膨胀的检查

提前安装好pgstattuple插件,用于返回一个关系的物理长度、"死亡"元组的百分比以及其他信息

create extension pgstattuple;

如下查询用于查看free_space占用前5的索引,空闲空间越大说明索引使用率越低

select oid::regclass,(pgstattuple(oid)).* from pg_class where relkind='i' order by free_space desc limit 5 offset 0;

如下查询查看具体表中的各个索引大小

select relname, pg_relation_size(oid)/1024 || 'K' AS size from pg_class where relkind='i' and relname='stu_dex';

除了扩展也可以通过如下的sql查看索引膨胀的相关信息(膨胀大小、膨胀率等),便于对膨胀的索引做优化

SELECT current_database(), nspname AS schemaname, tblname, idxname, bs*(relpages)::bigint AS real_size,bs*(relpages-est_pages)::bigint AS extra_size,100 * (relpages-est_pages)::float / relpages AS extra_pct,fillfactor,CASE WHEN relpages > est_pages_ffTHEN bs*(relpages-est_pages_ff)ELSE 0END AS bloat_size,100 * (relpages-est_pages_ff)::float / relpages AS bloat_pct,FROM (SELECT coalesce(1 +ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth)) AS est_pages,coalesce(1 +ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0) AS est_pages_ff,bs, nspname, tblname, idxname, relpages, fillfactor, is_na-- , pgstatindex(idxoid) AS pst, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO)FROM (SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, idxoid, fillfactor,( index_tuple_hdr_bm +maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGNWHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalignELSE index_tuple_hdr_bm%maxalignEND+ nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGNWHEN nulldatawidth = 0 THEN 0WHEN nulldatawidth::integer%maxalign = 0 THEN maxalignELSE nulldatawidth::integer%maxalignEND)::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na-- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO)FROM (SELECT n.nspname, i.tblname, i.idxname, i.reltuples, i.relpages,i.idxoid, i.fillfactor, current_setting('block_size')::numeric AS bs,CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?)WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8ELSE 4END AS maxalign,/* per page header, fixed size: 20 for 7.X, 24 for others */24 AS pagehdr,/* per page btree opaque data */16 AS pageopqdata,/* per tuple header: add IndexAttributeBitMapData if some cols are null-able */CASE WHEN max(coalesce(s.null_frac,0)) = 0THEN 8 -- IndexTupleData sizeELSE 8 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8)END AS index_tuple_hdr_bm,/* data len: we remove null values save space using it fractionnal part from stats */sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth,max( CASE WHEN i.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_naFROM (SELECT ct.relname AS tblname, ct.relnamespace, ic.idxname, ic.attpos, ic.indkey, ic.indkey[ic.attpos], ic.reltuples, ic.relpages, ic.tbloid, ic.idxoid, ic.fillfactor,coalesce(a1.attnum, a2.attnum) AS attnum, coalesce(a1.attname, a2.attname) AS attname, coalesce(a1.atttypid, a2.atttypid) AS atttypid,CASE WHEN a1.attnum IS NULLTHEN ic.idxnameELSE ct.relnameEND AS attrelnameFROM (SELECT idxname, reltuples, relpages, tbloid, idxoid, fillfactor, indkey,pg_catalog.generate_series(1,indnatts) AS attposFROM (SELECT ci.relname AS idxname, ci.reltuples, ci.relpages, i.indrelid AS tbloid,i.indexrelid AS idxoid,coalesce(substring(array_to_string(ci.reloptions, ' ')from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor,i.indnatts,pg_catalog.string_to_array(pg_catalog.textin(pg_catalog.int2vectorout(i.indkey)),' ')::int[] AS indkeyFROM pg_catalog.pg_index iJOIN pg_catalog.pg_class ci ON ci.oid = i.indexrelidWHERE ci.relam=(SELECT oid FROM pg_am WHERE amname = 'btree')AND ci.relpages > 0) AS idx_data) AS icJOIN pg_catalog.pg_class ct ON ct.oid = ic.tbloidLEFT JOIN pg_catalog.pg_attribute a1 ONic.indkey[ic.attpos] <> 0AND a1.attrelid = ic.tbloidAND a1.attnum = ic.indkey[ic.attpos]LEFT JOIN pg_catalog.pg_attribute a2 ONic.indkey[ic.attpos] = 0AND a2.attrelid = ic.idxoidAND a2.attnum = ic.attpos) iJOIN pg_catalog.pg_namespace n ON n.oid = i.relnamespaceJOIN pg_catalog.pg_stats s ON s.schemaname = n.nspnameAND s.tablename = i.attrelnameAND s.attname = i.attnameGROUP BY 1,2,3,4,5,6,7,8,9,10,11) AS rows_data_stats) AS rows_hdr_pdg_stats) AS relation_statsORDER BY nspname, tblname, idxname;

预防索引膨胀

实例级

vacuum命令运行的最小延迟:

alter system set autovacuum_naptime=15s;

在一个表上触发vacuum的被插入、被更新或被删除元组的最小数量:

alter system set autovacuum_vacuum_threshold=25;

在一个表上触发analyze的被插入、被更新或被删除元组的最小数量:

alter system set autovacuum_analyze_threshold=10;

决定是否触发vaccum时作为一个分数将它加到autovacuum_vacuum_threshold上:

alter system set autovacuum_vacuum_scale_factor=0.01;

决定是否触发analyze时作为一个分数将它加到autovacuum_vacuum_threshold上:

alter system set autovacuum_analyze_scale_factor=0.05;

autovacuum触发条件:

pg_stat_all_tables.n_dead_tup大于 autovacuum_vacuum_threshold + pg_class.reltuples * autovacuum_vacuum_scale_factor

autoananlyze触发条件:

pg_stat_all_tables.n_mod_since_analyze大于 autovacuum_analyze_threshold + pg_class.reltuples * autovacuum_analyze_scale_factor

表级

1、设置合适的autovacuum_vacuum_scale_factor,大表如果频繁的有更新或删除和插入操作, 建议设置较小的autovacuum_vacuum_scale_factor来降低空间的浪费,加快对表的vacuum操作频率

对更新频繁的表,单独调整

alter table tablename set (autovacuum_vacuum_scale_factor=0.05);

2、设置表的fillfactor,对频繁更新的表,调低fillfactor参数:

alter table tablename set (fillfactor=85);

解决索引膨胀

1、重建索引

创建新索引 create index CONCURRENTLY new_index ;

删除旧索引 drop index old_index ;

或者

重建索引 reindex index 索引名称 CONCURRENTLY ;

analyze tablename;

2、执行vacuum full

"完全"清理,这样可以恢复更多的空间,但是花的时间更多并且在表上施加了排它锁

http://www.xdnf.cn/news/487747.html

相关文章:

  • 哈希表实现(1):
  • 【言语】刷题5(填空)
  • 2025-05-15 代码人生 - 精选文章周刊
  • Microsoft Azure 服务4月更新告示
  • 简化WPF开发:CommunityToolkit属性绑定与命令声明实战
  • 服务器死机了需要检查哪些问题
  • pojo层、dao层、service层、controller层的作用
  • C++(15):默认值(default)
  • 等离子模块【杀菌消毒】
  • 大群将至:通付盾推出多智能体协同平台Legion
  • mysql隔离级别的学习分享
  • python可视化:北方省市人口流动与春运数据综合分析5
  • Java项目使用Tomcat启动后JS文件中的中文乱码问题
  • CRM客户管理系统有什么缺点?
  • 矩阵转置的LATEX写法
  • 阿里视频创建和编辑的一体化模型论文速读:Wan2.1-VACE-14B
  • 【24真题】华中师范大学838
  • 开发工具指南
  • 深入剖析与解决:`DELETE net::ERR_CONNECTION_RESET` 错误全指南
  • 【GNN笔记】Signed Graph Convolutional Network(12)【未完】
  • 框架的源码理解——V3中的ref和reactive
  • PHP中的SPL(标准PHP库):提升开发效率的工具集
  • base64加密为何可以直接找三方网站解密
  • 2025年上软考 考试时间+准考证打印全攻略
  • 基于 Flink 的实时推荐系统:从协同过滤到多模态语义理解
  • nnUNet V2修改网络——暴力替换网络为UCTransNet
  • 分布式 ID 生成的五种方法:优缺点与适用场景
  • Windows系统功能管控指南 | 一键隐藏关机键/禁用任务管理器
  • LLM学习笔记(五)概率论
  • 深入剖析Spring Boot参数校验:实现原理、自定义注解组件与国际化多语言实践