PgSQL · 应用案例 · 什么情况下可能表膨胀
背景
PostgreSQL heap TABLE AM引擎,使用多版本来解决快照问题,版本处于当前数据文件中,有垃圾回收进程进行回收,那么哪些垃圾不能被回收呢?
全局catalog 膨胀点
postgres=# select relname from pg_class where reltablespace in (select oid from pg_tablespace where spcname='pg_global') and relkind='r'; relname ----------------------- pg_authid pg_subscription pg_database pg_db_role_setting pg_tablespace pg_pltemplate pg_auth_members pg_shdepend pg_shdescription pg_replication_origin pg_shseclabel (11 rows)哪些垃圾不能被回收?
什么时候可能膨胀?
库级catalog 膨胀点
postgres=# select relname from pg_class where relkind='r' and relnamespace ='pg_catalog'::regnamespace except select relname from pg_class where reltablespace in (select oid from pg_tablespace where spcname = 'pg_global') and relkind='r';
relname ------------------------- pg_language pg_sequence pg_largeobject pg_policy pg_ts_template pg_attrdef pg_operator pg_ts_parser pg_depend pg_attribute pg_ts_config pg_conversion pg_inherits pg_subscription_rel pg_publication pg_foreign_table pg_largeobject_metadata pg_ts_dict pg_statistic pg_init_privs pg_opfamily pg_type pg_am pg_default_acl pg_proc pg_index pg_rewrite pg_statistic_ext pg_constraint pg_opclass pg_partitioned_table pg_namespace pg_trigger pg_enum pg_amop pg_event_trigger pg_collation pg_foreign_server pg_foreign_data_wrapper pg_user_mapping pg_description pg_cast pg_publication_rel pg_aggregate pg_transform pg_extension pg_class pg_seclabel pg_amproc pg_range pg_ts_config_map (51 rows)哪些垃圾不能被回收?
什么时候可能膨胀?
普通对象 膨胀点
哪些垃圾不能被回收?
什么时候可能膨胀?
WAL文件 膨胀点
哪些WAL不能被回收 或 不能被重复利用?
什么时候可能膨胀?
一些例子
postgres=# select pg_create_logical_replication_slot('a','test_decoding'); pg_create_logical_replication_slot ------------------------------------ (a,0/92C9C038) (1 row)2、查看slot的位点信息
postgres=# select * from pg_get_replication_slots(); slot_name | plugin | slot_type | datoid | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn -----------+---------------+-----------+--------+-----------+--------+------------+------+--------------+-------------+--------------------- a | test_decoding | logical | 13585 | f | f | | | 1982645 | 0/92C9BFE8 | /92C9C038 (1 row)postgres=# select pg_xact_commit_timestamp(xmin),pg_xact_commit_timestamp(catalog_xmin) from pg_get_replication_slots(); psql: ERROR: could not get commit timestamp data HINT: Make sure the configuration parameter "track_commit_timestamp" is set.postgres=# select pg_walfile_name(restart_lsn) from pg_get_replication_slots(); pg_walfile_name -------------------------- 000000010000000000000092 (1 row)
postgres=# select * from pg_stat_file('pg_wal/000000010000000000000092'); size | access | modification | change | creation | isdir ----------+------------------------+------------------------+------------------------+----------+------- 16777216 | 2019-06-29 22:56:16+08 | 2019-07-01 09:50:16+08 | 2019-07-01 09:50:16+08 | | f (1 row)
postgres=# select * from pg_ls_waldir() where name='000000010000000000000092'; name | size | modification --------------------------+----------+------------------------ 000000010000000000000092 | 16777216 | 2019-07-01 09:50:16+08 (1 row)postgres=# create table b(id int); CREATE TABLE postgres=# insert into b values (1); INSERT 1postgres=# select * from pg_logical_slot_get_changes('a',pg_current_wal_lsn(),1); lsn | xid | data ------------+---------+---------------- /92C9C0C | 1982645 | BEGIN 1982645 0/92CA4A40 | 1982645 | COMMIT 1982645 (2 rows)
postgres=# select * from pg_logical_slot_get_changes('a',pg_current_wal_lsn(),1); lsn | xid | data ------------+---------+--------------------------------------- /92CA4A78 | 1982646 | BEGIN 1982646 0/92CA4A78 | 1982646 | table public.b: INSERT: id[integer]:1 0/92CA4AE8 | 1982646 | COMMIT 1982646 (3 rows)postgres=# delete from b; DELETE 1postgres=# vacuum verbose b; psql: INFO: vacuuming "public.b" psql: INFO: "b": removed 1 row versions in 1 pages psql: INFO: "b": found 1 removable, nonremovable row versions in 1 out of 1 pages DETAIL: dead row versions cannot be removed yet, oldest xmin: 1982648 There were unused item identifiers. Skipped pages due to buffer pins, frozen pages. pages are entirely empty. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. psql: INFO: "b": truncated 1 to pages DETAIL: CPU: user: 0.09 s, system: 0.00 s, elapsed: 0.09 s VACUUMpostgres=# create table c (id int); CREATE TABLE postgres=# drop table c; DROP TABLE postgres=# create table c (id int); CREATE TABLE postgres=# drop table c; DROP TABLEpostgres=# vacuum verbose pg_class; psql: INFO: vacuuming "pg_catalog.pg_class" psql: INFO: "pg_class": found removable, 465 nonremovable row versions in 13 out of 13 pages DETAIL: 2 dead row versions cannot be removed yet, oldest xmin: 1982646 There were 111 unused item identifiers. Skipped pages due to buffer pins, frozen pages. pages are entirely empty. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. VACUUMpostgres=# vacuum verbose pg_attribute ; psql: INFO: vacuuming "pg_catalog.pg_attribute" psql: INFO: "pg_attribute": found removable, 293 nonremovable row versions in 6 out of 62 pages DETAIL: 14 dead row versions cannot be removed yet, oldest xmin: 1982646 There were 55 unused item identifiers. Skipped pages due to buffer pins, 55 frozen pages. pages are entirely empty. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. VACUUMpostgres=# begin; BEGIN postgres=# delete from a; DELETE 1db1=# create table b(id int); CREATE TABLE db1=# insert into b values (1); INSERT 1 db1=# delete from b; DELETE 1 db1=# vacuum verbose b; psql: INFO: vacuuming "public.b" psql: INFO: "b": removed 1 row versions in 1 pages psql: INFO: "b": found 1 removable, nonremovable row versions in 1 out of 1 pages DETAIL: dead row versions cannot be removed yet, oldest xmin: 1982671 There were unused item identifiers. Skipped pages due to buffer pins, frozen pages. pages are entirely empty. CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s. psql: INFO: "b": truncated 1 to pages DETAIL: CPU: user: 0.09 s, system: 0.00 s, elapsed: 0.09 s VACUUM小结
1 全局catalog 膨胀点
哪些垃圾不能被回收?
什么时候可能膨胀?
2 库级catalog 膨胀点
哪些垃圾不能被回收?
什么时候可能膨胀?
普通对象 膨胀点
哪些垃圾不能被回收?
什么时候可能膨胀?
WAL文件 膨胀点
哪些WAL不能被回收 或 不能被重复利用?
什么时候可能膨胀?
参考
switch (HeapTupleSatisfiesVacuum(&tuple, OldestXmin, buf)) { case HEAPTUPLE_DEAD:
/* * Ordinarily, DEAD tuples would have been removed by * heap_page_prune(), but it's possible that the tuple * state changed since heap_page_prune() looked. In * particular an INSERT_IN_PROGRESS tuple could have * changed to DEAD if the inserter aborted. So this * cannot be considered an error condition. * * If the tuple is HOT-updated then it must only be * removed by a prune operation; so we keep it just as if * it were RECENTLY_DEAD. Also, if it's a heap-only * tuple, we choose to keep it, because it'll be a lot * cheaper to get rid of it in the next pruning pass than * to treat it like an indexed tuple. Finally, if index * cleanup is disabled, the second heap pass will not * execute, and the tuple will not get removed, so we must * treat it like any other dead tuple that we choose to * keep. * * If this were to happen for a tuple that actually needed * to be deleted, we'd be in trouble, because it'd * possibly leave a tuple below the relation's xmin * horizon alive. heap_prepare_freeze_tuple() is prepared * to detect that case and abort the transaction, * preventing corruption. */ if (HeapTupleIsHotUpdated(&tuple) || HeapTupleIsHeapOnly(&tuple) || params->index_cleanup == VACOPT_TERNARY_DISABLED) nkeep += 1; else tupgone = true; /* we can delete the tuple */ all_visible = false; break;
case HEAPTUPLE_RECENTLY_DEAD:
/* * If tuple is recently deleted then we must not remove it * from relation. */ nkeep += 1; all_visible = false; break;* HeapTupleSatisfiesVacuum() * visible to any running transaction, used by VACUUM/* * HeapTupleSatisfiesVacuum * * Determine the status of tuples for VACUUM purposes. Here, what * we mainly want to know is if a tuple is potentially visible to *any* * running transaction. If so, it can't be removed yet by VACUUM. * * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might * still be visible to some open transaction, so we can't remove them, * even if we see that the deleting transaction has committed. */ HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
/* * Deleter committed, but perhaps it was recent enough that some open * transactions could still see the tuple. */ if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin)) return HEAPTUPLE_RECENTLY_DEAD;
else if (TransactionIdDidCommit(xmax)) { /* * The multixact might still be running due to lockers. If the * updater is below the xid horizon, we have to return DEAD * regardless -- otherwise we could end up with a tuple where the * updater has to be removed due to the horizon, but is not pruned * away. It's not a problem to prune that tuple, because any * remaining lockers will also be present in newer tuple versions. */ if (!TransactionIdPrecedes(xmax, OldestXmin)) return HEAPTUPLE_RECENTLY_DEAD;
return HEAPTUPLE_DEAD; }Hot Standby feedback message (F) Byte1('h') Identifies the message as a Hot Standby feedback message.
Int64 The client's system clock at the time of transmission, as microseconds since midnight on 2000-01-01.
Int32 The standby's current global xmin, excluding the catalog_xmin from any replication slots. If both this value and the following catalog_xmin are this is treated as a notification that Hot Standby feedback will no longer be sent on this connection. Later non-zero messages may reinitiate the feedback mechanism.
Int32 The epoch of the global xmin xid on the standby.
Int32 The lowest catalog_xmin of any replication slots on the standby. Set to if no catalog_xmin exists on the standby or if hot standby feedback is being disabled.
Int32 The epoch of the catalog_xmin xid on the standby. 相关文章