修改源代码,优化 Autovacuum 触发条件
前言
此文章为读者投稿 (欢迎各位读者投稿👏🏻),Author:邱神医,数据库里最懂医学,医学里最懂数据库,被数据库耽搁的神医。PostgreSQL 的 MVCC 实现方式就像信用卡,删除、更新和回滚留下的"债务"需要去偿还,偿还的动作便是由 vacuum / autovacuum 来做的,如果不偿还就会导致破产。
autovacuum 的触发机制有几个参数控制
• autovacuum_vacuum_threshold 和 toast.autovacuum_vacuum_threshold • autovacuum_vacuum_scale_factor 和 toast.autovacuum_vacuum_scale_factor今天这篇文章由邱神医投稿,演示了如何修改源代码以调整触发 autovacuum 的算法。
当前计算方法是基于线性增长的阈值对大表并不友好。设想一个包含数亿行的大表,其清理阈值将随着表行数增加而增大,导致自动清理触发的时间过长。这不仅影响了存储空间的利用率,还使查询优化器无法得到及时更新的统计信息进行优化,进而影响数据库的查询性能。
正文
PostgreSQL 的 MVCC 机制 (这段偷懒,引用 cc 的文章)
1. 插入是将元组插入到页面的空闲空间中; 2. 删除则是直接将元组标记为旧版本,即使这个旧版本对所有事务都不可见了,这个元组占用的空间也不会归还给文件系统 3. UPDATE相当于DELETE + INSERT,等于是占用了两条元组的位置,类似DELETE,旧版本的元组依然占用着物理空间。表经过增删改操作之后,页面上的旧版本元组势必是占有一定比重的。这就导致了物理文件大小明显高于实际的数据量。
为此,PostgreSQL 引入了 vacuum 的机制,去清理那些不再需要的死元组,在 8.1 版本之后引入了 autovacuum,到目前为止,现有的代码触发 autovacuum 计算公式:
1. vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples; 2. anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;通过画出函数图像,可以得知是一次函数图像,当前计算方法是基于线性增长的阈值对大表并不友好。设想一个包含数亿行的大表,其清理阈值将随着表行数增加而增大,导致自动清理触发的时间过长。这不仅影响了存储空间的利用率,还使查询优化器无法得到及时更新的统计信息进行优化,进而影响数据库的查询性能。
在我们中学阶段,就学习了几个函数,算术平方根,对数函数,幂函数,我们以幂函数来看,在使用幂次公式的情况下,阈值在表行数较小时与线性模型接近,但随着表行数的进一步增加,幂次增长公式的阈值增长速度减缓。对大表来说,这意味着清理和分析操作会更频繁地触发。通过计算公式可以推算实际数据库中的大表更新,我们发现使用幂次公式后,数据库的大表能够更及时地进行清理操作,避免了表膨胀现象。同时,统计信息的更新也更加及时,优化器在查询时能够基于最新的统计信息做出更好的查询计划,从而提升整体查询性能。
源码实现
我们查看
autovacuum.c
,总共 3041 行,现有的计算方法是一次函数,我们直接去修改计算公式,PG 社区老顽固肯定不会同意,你这么一改,回不到原来的行为,而且这么一改,只有一种算法,不符合成年人的选择,上面计算公式我全都要,那么我们就需要引入一个参数,可以选择其中一个计算方法:
首先我们要在vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;vacinsthresh = (float4) vac_ins_base_thresh + vac_ins_scale_factor * reltuples;anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
guc_tables.c
新增一个参数,新增参数最好是枚举类型,防止瞎填导致出现问题,通过
guc.c
源码,我们可以知道 guc 参数有这些,我们在
guc_tables.c
源码文件中添加我们新的参数
/** Detect whether an "extra" struct is referenced anywhere in a GUC item*/static boolextra_field_used(struct config_generic *gconf, void *extra){GucStack *stack;if (extra == gconf->extra)return true;switch (gconf->vartype){case PGC_BOOL:if (extra == ((struct config_bool *) gconf)->reset_extra)return true;break;case PGC_INT:if (extra == ((struct config_int *) gconf)->reset_extra)return true;break;case PGC_REAL:if (extra == ((struct config_real *) gconf)->reset_extra)return true;break;case PGC_STRING:if (extra == ((struct config_string *) gconf)->reset_extra)return true;break;case PGC_ENUM:if (extra == ((struct config_enum *) gconf)->reset_extra)return true;break;}for (stack = gconf->stack; stack; stack = stack->prev){if (extra == stack->prior.extra ||extra == stack->masked.extra)return true;}return false;}/** Support for assigning to an "extra" field of a GUC item. Free the prior* value if it's not referenced anywhere else in the item (including stacked* states).*/
在 struct config_enum ConfigureNamesEnum[] = 里面新增一个参数叫 autovacuum_algorithm
同时我们要在/* add guc for autovacuum algorithm*/{{"autovacuum_algorithm", PGC_SIGHUP, AUTOVACUUM,gettext_noop("vacuum trigger algorithm."),NULL},&autovacuum_algorithm,AUTOVACUUM_ALGORITHM_LINEAR, autovacuum_algorithm_options,NULL, NULL, NULL},/* End-of-list marker */{{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL}
guc_tables.c
添加一个枚举类型:
在参数层面我们已经成功添加了,static const struct config_enum_entry wal_compression_options[] = {{"pglz", WAL_COMPRESSION_PGLZ, false},#ifdef USE_LZ4{"lz4", WAL_COMPRESSION_LZ4, false},#endif#ifdef USE_ZSTD{"zstd", WAL_COMPRESSION_ZSTD, false},#endif{"on", WAL_COMPRESSION_PGLZ, false},{"off", WAL_COMPRESSION_NONE, false},{"true", WAL_COMPRESSION_PGLZ, true},{"false", WAL_COMPRESSION_NONE, true},{"yes", WAL_COMPRESSION_PGLZ, true},{"no", WAL_COMPRESSION_NONE, true},{"1", WAL_COMPRESSION_PGLZ, true},{"0", WAL_COMPRESSION_NONE, true},{NULL, 0, false}};/* vacuum_algorithm guc */static const struct config_enum_entry autovacuum_algorithm_options[] = {{"log2", AUTOVACUUM_ALGORITHM_LOG2, false},{"sqrt", AUTOVACUUM_ALGORITHM_SQRT, false},{"linear", AUTOVACUUM_ALGORITHM_LINEAR, false},{"pow", AUTOVACUUM_ALGORITHM_POW, false},{NULL, 0, false}};
autovacuum.h
去定义新增参数
在/* algorithms for Vacuum */typedef enum Autovacuum_algorithm{AUTOVACUUM_ALGORITHM_LINEAR,AUTOVACUUM_ALGORITHM_LOG2,AUTOVACUUM_ALGORITHM_SQRT,AUTOVACUUM_ALGORITHM_POW} Autovacuum_algorithm;extern PGDLLIMPORT int autovacuum_algorithm;/* Status inquiry functions */extern bool AutoVacuumingActive(void);
autovacuum.c
定义一个全局变量,改原有计算公式。vacinsthresh 因为是优化插入数据触发收集统计信息,保留原来算法更合适
int Log_autovacuum_min_duration = 600000;/* guc parameter of autovacuum_algorithm */int autovacuum_algorithm = AUTOVACUUM_ALGORITHM_LINEAR;/* the minimum allowed time between two awakenings of the launcher */#define MIN_AUTOVAC_SLEEPTIME 100.0 /* milliseconds */#define MAX_AUTOVAC_SLEEPTIME 300 /* seconds *//* If the table hasn't yet been vacuumed, take reltuples as zero */if (reltuples < 0)reltuples = 0;switch (autovacuum_algorithm){case AUTOVACUUM_ALGORITHM_LOG2:vacthresh = (float4) fmin(vac_base_thresh + (vac_scale_factor * reltuples), vac_base_thresh + vac_scale_factor * log2(reltuples) * 100000.0 );anlthresh = (float4) fmin(anl_base_thresh + (anl_scale_factor * reltuples), anl_base_thresh + anl_scale_factor * log2(reltuples) * 100000.0 );elog(DEBUG2, "Using log2 algorithm for vacuum,vacthresh values is %f,anlthresh values is %f",vacthresh,anlthresh);break;case AUTOVACUUM_ALGORITHM_SQRT:vacthresh = (float4) fmin(vac_base_thresh + (vac_scale_factor * reltuples), vac_base_thresh + vac_scale_factor * sqrt(reltuples) * 1000.0 );anlthresh = (float4) fmin(anl_base_thresh + (anl_scale_factor * reltuples), vac_base_thresh + anl_scale_factor * sqrt(reltuples) * 1000.0 );elog(DEBUG2, "Using sqrt algorithm for vacuum,vacthresh values is %f,anlthresh values is %f",vacthresh,anlthresh);break;case AUTOVACUUM_ALGORITHM_LINEAR:vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;elog(DEBUG2, "Using linear algorithm for vacuum,vacthresh values is %f,anlthresh values is %f",vacthresh,anlthresh);break;case AUTOVACUUM_ALGORITHM_POW:vacthresh = (float4) fmin(vac_base_thresh + (vac_scale_factor * reltuples), vac_base_thresh + vac_scale_factor * pow(reltuples,0.7) * 100.0 );anlthresh = (float4) fmin(anl_base_thresh + (anl_scale_factor * reltuples), vac_base_thresh + anl_scale_factor * pow(reltuples,0.7) * 100.0 );elog(DEBUG2, "Using pow algorithm for vacuum,vacthresh values is %f,anlthresh values is %f",vacthresh,anlthresh);break;default:elog(ERROR, "Unknown vacuum_algorithm value.");}vacinsthresh = (float4) vac_ins_base_thresh + vac_ins_scale_factor * reltuples;/** Note that we don't need to take special consideration for stat* reset, because if that happens, the last vacuum and analyze counts* will be reset too.*/
最后我们要去修改一下配置文件模板,添加我们新增参数
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for# autovacuum, -1 means use# vacuum_cost_limit#autovacuum_algorithm = linear # autovacuum_algorithm for (log2,sqrt,linear,pow) default linear
编译代码,初始化库之后,我们尝试设置为算术平方根。
postgres=# show autovacuum_algorithm ;autovacuum_algorithm----------------------linear(1 row)postgres=# alter system set autovacuum_algorithm TO sqrt;ALTER SYSTEMpostgres=# select pg_reload_conf();pg_reload_conf----------------t(1 row)postgres=# show autovacuum_algorithm ;autovacuum_algorithm----------------------sqrt(1 row)
仅仅有这个参数,那么我们怎么知道我们改的逻辑正确的呢 — 在代码里面加了 debug2 日志
postgres=# show log_min_messages ;log_min_messages------------------warning(1 row)postgres=# alter system set log_min_messages TO debug2 ;ALTER SYSTEMpostgres=# select pg_reload_conf();pg_reload_conf----------------t(1 row)postgres=# show log_min_messages ;log_min_messages------------------debug2(1 row)
从日志来看,我们新增的算法是生效的
2024-11-26 18:18:04.233 +08,,,205680,,6745a05c.32370,92,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.233 +08,,,205680,,6745a05c.32370,93,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.233 +08,,,205680,,6745a05c.32370,94,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,95,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,96,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,97,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,98,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,99,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,100,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,101,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,102,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,103,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,104,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,105,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,106,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,107,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,108,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,02024-11-26 18:18:04.234 +08,,,205680,,6745a05c.32370,109,,2024-11-26 18:18:04 +08,1005/44261,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 50.000000,anlthresh values is 50.000000",,,,,,,,,"","autovacuum worker",,0
验证
让我们新建一个表并插入一千万行记录,验证一下:
sysbench=# CREATE TABLE t11(id bigserial NOT NULL primary key,cid text);CREATE TABLEsysbench=# insert into t11 SELECT generate_series(1,10000000) as id,md5(random()::text);INSERT 0 10000000# INSERT 同样会触发统计信息更新sysbench=# select * from pg_stat_user_tables where relname='t11';-[ RECORD 1 ]-------+------------------------------relid | 16428schemaname | publicrelname | t11seq_scan | 1last_seq_scan | 2024-11-27 09:44:44.605001+08seq_tup_read | 0idx_scan | 0last_idx_scan |idx_tup_fetch | 0n_tup_ins | 10000000n_tup_upd | 0n_tup_del | 0n_tup_hot_upd | 0n_tup_newpage_upd | 0n_live_tup | 10000006n_dead_tup | 0n_mod_since_analyze | 0n_ins_since_vacuum | 0last_vacuum |last_autovacuum | 2024-11-27 09:49:14.562558+08last_analyze |last_autoanalyze | 2024-11-27 09:49:14.795829+08vacuum_count | 0autovacuum_count | 1analyze_count | 0autoanalyze_count | 1
通过计算,如果选用算术平方根算法,需要更新这么多行数据就会触发 vacuum
sysbench=# select 50+sqrt(10000000)*1000*0.2;-[ RECORD 1 ]---------------?column? | 632505.5320336759sysbench=# update t11 set cid=md5(random()::text) where id<=632500;UPDATE 632500sysbench=# select * from pg_stat_user_tables where relname='t11';-[ RECORD 1 ]-------+------------------------------relid | 16428schemaname | publicrelname | t11seq_scan | 1last_seq_scan | 2024-11-27 09:44:44.605001+08seq_tup_read | 0idx_scan | 1last_idx_scan | 2024-11-27 09:52:49.728153+08idx_tup_fetch | 632500n_tup_ins | 10000000n_tup_upd | 632500n_tup_del | 0n_tup_hot_upd | 0n_tup_newpage_upd | 632500n_live_tup | 10000006n_dead_tup | 632500n_mod_since_analyze | 632500n_ins_since_vacuum | 0last_vacuum |last_autovacuum | 2024-11-27 09:49:14.562558+08last_analyze |last_autoanalyze | 2024-11-27 09:49:14.795829+08vacuum_count | 0autovacuum_count | 1analyze_count | 0autoanalyze_count | 1# 再更新50行,达到触发阈值sysbench=# update t11 set cid=md5(random()::text) where id>=632500 and id<=632500+20;UPDATE 21sysbench=# select * from pg_stat_user_tables where relname='t11';-[ RECORD 1 ]-------+------------------------------relid | 16428schemaname | publicrelname | t11seq_scan | 2last_seq_scan | 2024-11-27 09:53:27.640239+08seq_tup_read | 1286710idx_scan | 2last_idx_scan | 2024-11-27 09:53:59.004808+08idx_tup_fetch | 632521n_tup_ins | 10000000n_tup_upd | 1919212n_tup_del | 0n_tup_hot_upd | 42n_tup_newpage_upd | 1919170n_live_tup | 10005976n_dead_tup | 1913304n_mod_since_analyze | 21n_ins_since_vacuum | 0last_vacuum |last_autovacuum | 2024-11-27 09:49:14.562558+08last_analyze |last_autoanalyze | 2024-11-27 09:53:14.043256+08vacuum_count | 0autovacuum_count | 1analyze_count | 0autoanalyze_count | 2sysbench=# select * from pg_stat_user_tables where relname='t11'; ---触发了autovacuum-[ RECORD 1 ]-------+------------------------------relid | 16428schemaname | publicrelname | t11seq_scan | 2last_seq_scan | 2024-11-27 09:53:27.640239+08seq_tup_read | 1286710idx_scan | 2last_idx_scan | 2024-11-27 09:53:59.004808+08idx_tup_fetch | 632521n_tup_ins | 10000000n_tup_upd | 1919212n_tup_del | 0n_tup_hot_upd | 42n_tup_newpage_upd | 1919170n_live_tup | 9523781n_dead_tup | 0n_mod_since_analyze | 21n_ins_since_vacuum | 0last_vacuum |last_autovacuum | 2024-11-27 09:54:14.942846+08last_analyze |last_autoanalyze | 2024-11-27 09:53:14.043256+08vacuum_count | 0autovacuum_count | 2analyze_count | 0autoanalyze_count | 2
如果原有算法,触发 vacuum 和收集统计信息需要更新这么多行数据
sysbench=# select 50+0.2*10000000;-[ RECORD 1 ]-------?column? | 2000050.0sysbench=# select 50+0.1*10000000;-[ RECORD 1 ]-------?column? | 1000050.0
在日志文件里面,也可以得到验证,现在就看社区大佬什么意见了。
2024-11-27 09:54:13.751 +08,,,318543,,67467bc5.4dc4f,8,,2024-11-27 09:54:13 +08,1001/60,0,DEBUG,00000,"the relname is t11 has 10005976.000000 reltuples ",,,,,,,,,"","autovacuum worker",,02024-11-27 09:54:13.751 +08,,,318543,,67467bc5.4dc4f,9,,2024-11-27 09:54:13 +08,1001/60,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 632694.500000,anlthresh values is 316372.250000, the t11 has 10005976.000000 reltuples",,,,,,,,,"","autovacuum worker",,02024-11-27 09:54:13.752 +08,,,318543,,67467bc5.4dc4f,108,,2024-11-27 09:54:13 +08,1001/60,0,DEBUG,00000,"the relname is t11 has 10005976.000000 reltuples ",,,,,,,,,"","autovacuum worker",,02024-11-27 09:54:13.752 +08,,,318543,,67467bc5.4dc4f,109,,2024-11-27 09:54:13 +08,1001/60,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 632694.500000,anlthresh values is 316372.250000, the t11 has 10005976.000000 reltuples",,,,,,,,,"","autovacuum worker",,02024-11-27 09:54:14.892 +08,,,318543,,67467bc5.4dc4f,112,,2024-11-27 09:54:13 +08,1001/61,0,DEBUG,00000,"scanned index ""t11_pkey"" to remove 1919170 row versions",,,,,"while vacuuming index ""t11_pkey"" of relation ""public.t11""",,,,"","autovacuum worker",,02024-11-27 09:54:14.942 +08,,,318543,,67467bc5.4dc4f,113,,2024-11-27 09:54:13 +08,1001/61,0,DEBUG,00000,"table ""t11"": removed 1919170 dead item identifiers in 17938 pages",,,,,"while vacuuming relation ""public.t11""",,,,"","autovacuum worker",,02024-11-27 09:54:14.942 +08,,,318543,,67467bc5.4dc4f,114,,2024-11-27 09:54:13 +08,1001/61,0,DEBUG,00000,"index ""t11_pkey"" now contains 10000000 row versions in 32683 pages","1919170 index row versions were removed.0 index pages are currently deleted, of which 0 are currently reusable.",,,,"while cleaning up index ""t11_pkey"" of relation ""public.t11""",,,,"","autovacuum worker",,02024-11-27 09:55:13.770 +08,,,318605,,67467c01.4dc8d,8,,2024-11-27 09:55:13 +08,1002/67,0,DEBUG,00000,"the relname is t11 has 9523781.000000 reltuples ",,,,,,,,,"","autovacuum worker",,02024-11-27 09:55:13.770 +08,,,318605,,67467c01.4dc8d,9,,2024-11-27 09:55:13 +08,1002/67,0,DEBUG,00000,"Using sqrt algorithm for vacuum, vacthresh values is 617262.500000,anlthresh values is 308656.250000, the t11 has 9523781.000000 reltuples",,,,,,,,,"","autovacuum worker",,0
至于日志里面多出来的表名字,是我为了debug 加的,实现也很简单,具体代码如下
if (PointerIsValid(tabentry) && AutoVacuumingActive()){reltuples = classForm->reltuples;vactuples = tabentry->dead_tuples;instuples = tabentry->ins_since_vacuum;anltuples = tabentry->mod_since_analyze;char relname_str[NAMEDATALEN];strncpy(relname_str, classForm->relname.data, NAMEDATALEN);relname_str[NAMEDATALEN - 1] = '\0';elog(DEBUG2, "the relname is %s has %f reltuples ", relname_str, reltuples);/* If the table hasn't yet been vacuumed, take reltuples as zero */if (reltuples < 0)reltuples = 0;switch (autovacuum_algorithm){case AUTOVACUUM_ALGORITHM_LOG2:vacthresh = (float4) fmin(vac_base_thresh + (vac_scale_factor * reltuples), vac_base_thresh + vac_scale_factor * log2(reltuples) * 10000.0 );anlthresh = (float4) fmin(anl_base_thresh + (anl_scale_factor * reltuples), anl_base_thresh + anl_scale_factor * log2(reltuples) * 10000.0 );elog(DEBUG2, "Using log2 algorithm for vacuum, vacthresh values is %f,anlthresh values is %f, the %s has %f reltuples " ,vacthresh, anlthresh, relname_str , reltuples );break;case AUTOVACUUM_ALGORITHM_SQRT:vacthresh = (float4) fmin(vac_base_thresh + (vac_scale_factor * reltuples), vac_base_thresh + vac_scale_factor * sqrt(reltuples) * 1000.0 );anlthresh = (float4) fmin(anl_base_thresh + (anl_scale_factor * reltuples), anl_base_thresh + anl_scale_factor * sqrt(reltuples) * 1000.0 );elog(DEBUG2, "Using sqrt algorithm for vacuum, vacthresh values is %f,anlthresh values is %f, the %s has %f reltuples" , vacthresh, anlthresh, relname_str, reltuples );break;case AUTOVACUUM_ALGORITHM_LINEAR:vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;elog(DEBUG2, "Using linear algorithm for vacuum, vacthresh values is %f,anlthresh values is %f, the %s has %f reltuples", vacthresh, anlthresh, relname_str , reltuples );break;case AUTOVACUUM_ALGORITHM_POW:vacthresh = (float4) fmin(vac_base_thresh + (vac_scale_factor * reltuples), vac_base_thresh + vac_scale_factor * pow(reltuples, 0.7) * 100.0 );anlthresh = (float4) fmin(anl_base_thresh + (anl_scale_factor * reltuples), anl_base_thresh + anl_scale_factor * pow(reltuples, 0.7) * 100.0 );elog(DEBUG2, "Using pow algorithm for vacuum, vacthresh values is %f,anlthresh values is %f, the %s has %f reltuples", vacthresh, anlthresh, relname_str, reltuples);break;default:elog(ERROR, "Unknown vacuum_algorithm value.");break;}vacinsthresh = (float4) vac_ins_base_thresh + vac_ins_scale_factor * reltuples;
老熊有话说
autovacuum 的调优一直是一门大学问,说白了,autovacuum 只是根据相关配置参数自动运行 VACUUM/ANALYZE 的后台进程,因此,它也可能会因为各种各样的原因失败、阻塞、忙等,需对症下药。
• Slow or Stuck . VACUUM runs for a very long time on a table, maybe forever,比如较慢的磁盘,锁阻塞、配置参数过于保守等等 • Spinning . Same VACUUM is getting retried over and over again, either because either because it’s failing with an error, or because it’s succeeding but nothing useful is happening,比如2PC、复制槽和长事务等等,也可能因为报错反复重启,就好比 logical replication worker • Skipped . Autovacuum doesn’t think that VACUUM is required, but actually it is,没有达到触发阈值,或者没有足够的工作进程等等。 • Starvation . Autovacuum is too busy and so some tables are not getting checked. 希望邱神医这篇文章能够给各位读者带来些许思路。