From f3a5b9da6b195995e9af0b69115050b98e858c36 Mon Sep 17 00:00:00 2001 From: hanjianqiao Date: Tue, 8 Sep 2026 09:01:31 +0800 Subject: [PATCH 1/2] add pg_track_settings CN --- CN/modules/ROOT/nav.adoc | 1 + .../ecosystem_overview.adoc | 1 + .../pg_track_settings.adoc | 195 ++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc diff --git a/CN/modules/ROOT/nav.adoc b/CN/modules/ROOT/nav.adoc index 68f93003..cee846c6 100644 --- a/CN/modules/ROOT/nav.adoc +++ b/CN/modules/ROOT/nav.adoc @@ -76,6 +76,7 @@ *** xref:master/ecosystem_components/zhparser.adoc[zhparser] *** xref:master/ecosystem_components/pgbackrest.adoc[pgBackRest] *** xref:master/ecosystem_components/set_user.adoc[set_user] +*** xref:master/ecosystem_components/pg_track_settings.adoc[pg_track_settings] * 监控运维 ** xref:master/getting-started/daily_monitoring.adoc[日常监控] ** xref:master/getting-started/daily_maintenance.adoc[日常维护] diff --git a/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc b/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc index 074ce67c..6b886326 100644 --- a/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc +++ b/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc @@ -41,6 +41,7 @@ IvorySQL 作为一款兼容 Oracle 且基于 PostgreSQL 的高级开源数据库 | 28 | xref:master/ecosystem_components/zhparser.adoc[zhparser] | master branch | 用于中文全文搜索的PostgreSQL插件,基于SCWS(即:简易中文分词系统)实现了一个中文解析器 | 搜索引擎、关键字提取 | 29 | xref:master/ecosystem_components/pgbackrest.adoc[pgBackRest] | 2.58.0 | 可靠的 PostgreSQL 备份和恢复解决方案 | 容灾备份、大库备份、异地/多层容灾 | 30 | xref:master/ecosystem_components/set_user.adoc[set_user] | REL4_2_0 | PostgreSQL 安全审计扩展,可控角色切换,支持白名单、强制审计、拦截高危操作 | 可控角色切换、权限管理、审计日志 +| 31 | xref:master/ecosystem_components/pg_track_settings.adoc[pg_track_settings] | 2.1.2 | PostgreSQL 配置跟踪扩展,记录配置变更历史 | 配置审计、变更追踪 |==== 这些插件均经过 IvorySQL 团队的测试和适配,确保在 IvorySQL 环境下稳定运行。用户可以根据业务需求选择合适的插件,进一步提升数据库系统的能力和灵活性。 diff --git a/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc b/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc new file mode 100644 index 00000000..fabd45d4 --- /dev/null +++ b/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc @@ -0,0 +1,195 @@ + +:sectnums: +:sectnumlevels: 5 + += pg_track_settings + +== 概述 +pg_track_settings 是一个仅由约500行 PL/pgSQL 编写的 PG 扩展,可以实现对 PostgreSQL 配置变更的跟踪。 + +它提供了一个函数 (pg_track_settings_snapshot()),必须定期调用。每次调用时,它都会存储自上次调用以来更改的设置。如果 PostgreSQL 的启动时间与上次不同,它还会跟踪本次启动时间。pg_track_settings 通常需要和 Cron 或 PoWA 等工具配合使用,以便在生产环境中定期采样。 + +IvorySQL 的 PG 模式和 Oracle 兼容模式都已经适配 pg_track_settings。 + +项目地址: + +开源协议:PostgreSQL License + +== 函数一览 + +=== 全局参数 + +[options="header"] +|=== +| 函数 | 作用 +| pg_track_settings_snapshot() | 采集当前配置,记录差异 +| pg_track_settings(timestamptz) | 返回指定时刻的全量配置;省略参数则为当前时刻 +| pg_track_settings_diff(timestamptz, timestamptz) | 返回两个时刻之间发生变化的所有参数 +| pg_track_settings_log(text) | 返回某个指定参数的完整变更历史 +|=== + +=== 库级/角色级覆盖参数 + +[options="header"] +|=== +| 函数 | 作用 +| pg_track_db_role_settings(timestamptz) | 指定时刻的全部覆盖配置 +| pg_track_db_role_settings_diff(timestamptz, timestamptz) | 两个时刻之间变化的覆盖配置 +| pg_track_db_role_settings_log(text) | 某个覆盖参数的变更历史 +|=== + +=== 维护 + +[options="header"] +|=== +| 函数 | 作用 +| pg_track_settings_reset() | 清空全部历史记录 +|=== + +== 安装启用 + +=== 源码编译 + +执行源码编译和安装: +[literal, bash] +---- +# 构建并安装 pg_track_settings +cd ivorysql +git clone https://github.com/rjuju/pg_track_settings.git contrib/pg_track_settings +make -C contrib/pg_track_settings install +---- + +=== 安装扩展 + +PG 模式与 Oracle 模式会话下命令相同: +[literal, sql] +---- +CREATE EXTENSION pg_track_settings; + + extname | extversion +-------------------+------------ + pg_track_settings | 2.1.2 +---- + +== 使用流程 + +[TIP] +==== +以下输出为示意,用于说明各函数的返回形式。 +==== + +先做一次快照,建立基线: + +[literal, sql] +---- +postgres=# SELECT pg_track_settings_snapshot(); + pg_track_settings_snapshot +---------------------------- + t +(1 row) +---- + +此时历史表里已经有了第一批记录: + +[literal, sql] +---- +postgres=# SELECT DISTINCT ts FROM pg_track_settings_history; + ts +------------------------------- + 2026-09-08 10:00:37.449846+08 +(1 row) +---- + +假设现在有人改了配置并重载: + +[literal, sql] +---- +postgres=# ALTER SYSTEM SET work_mem = '32MB'; +postgres=# SELECT pg_reload_conf(); +---- + +再采集一次,然后查看这段时间内的变更: + +[TIP] +==== +在Oracle兼容模式下需要使用 make_interval(mins => 10) 来代替 interval '10 minutes',否则会报错。 +==== + +[literal, sql] +---- +postgres=# SELECT pg_track_settings_snapshot(); + +postgres=# SELECT * FROM pg_track_settings_diff(now() - interval '10 minutes', now()); + name | from_setting | from_exists | to_setting | to_exists +----------+--------------+-------------+------------+----------- + work_mem | 4096 | t | 32768 | t +(1 row) +---- + +from_exists / to_exists 这两列用来表达参数在两个时间点是否存在。参数被新增时 from_exists 为 false,被移除时 to_exists 为 false —— 这正是前面提到的墓碑记录发挥作用的地方。 + +查看单个参数的完整历史: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_track_settings_log('work_mem'); + ts | name | setting_exists | setting +-------------------------------+----------+----------------+--------- + 2026-09-08 10:06:42.581682+08 | work_mem | t | 32768 + 2026-09-08 10:00:37.449846+08 | work_mem | t | 4096 +(2 rows) +---- + +回溯任意时刻的完整配置: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_track_settings('2026-09-08 10:03:00'); + name | setting +------------------------------+--------- + [...] + checkpoint_completion_target | 0.9 + checkpoint_timeout | 300 + work_mem | 4096 + [...] +---- + +查看覆盖参数的历史: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_track_db_role_settings_log('statement_timeout'); + ts | dbname | rolname | name | setting_exists | setting +-------------------------------+----------+----------+-------------------+----------------+--------- + 2026-09-08 11:15:03.112094+08 | appdb | | statement_timeout | t | 30s +---- + +查看实例重启历史: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_reboot; + ts +------------------------------- + 2026-09-08 09:39:43.609195+08 +(1 row) +---- + +== 注意事项 + +**关于备份:** 所有历史数据都存在普通表里,因此会被 pg_dump / pg_dumpall 完整备份。这通常是好事,但如果积累了很长的历史又不想带进备份,需要使用 pg_track_settings_reset() 清理。 + +**关于时间戳:** 历史表的 ts 列是 timestamptz 类型,存的是绝对时间点,显示时按会话时区换算。跨时区团队查历史时,注意各自会话的 TimeZone 设置可能导致看到的字符串不同,但指向的是同一时刻。 + +**关于采集间隔:** 扩展记录的是「发现变更的时刻」,不是「变更实际发生的时刻」。如果两次快照之间某个参数改了又改回来,中间状态会被完全丢失。对配置审计要求严格的场景,应该配合 log_statement = 'ddl' 或专门的审计扩展一起用。 + +**关于权限:** control 文件中 superuser = false,即非超级用户也可以创建该扩展(前提是拥有目标 schema 的权限)。但采集函数需要能读取 pg_settings 和 pg_db_role_setting,实际执行时仍建议用有足够权限的角色。 + +**它不是什么:** 这个扩展只做记录,不做告警,也不会阻止任何配置修改。它是事后排查的工具,不是准入控制。 + +== 适合场景 + +- 多人共同运维、配置变更缺乏统一流程的团队 +- 需要做性能回归分析,想确认「变慢是不是因为改了参数」的 DBA +- 管理大量实例、需要集中掌握配置漂移情况的场景(配合 PoWA) +- 有合规审计要求,需要证明某个时间点配置状态的环境 From b805bb2071bd03288634096f54b4ceadd94b7f18 Mon Sep 17 00:00:00 2001 From: hanjianqiao Date: Tue, 8 Sep 2026 09:14:08 +0800 Subject: [PATCH 2/2] typo fix and add EN ver --- .../pg_track_settings.adoc | 22 +- EN/modules/ROOT/nav.adoc | 1 + .../ecosystem_overview.adoc | 1 + .../pg_track_settings.adoc | 194 ++++++++++++++++++ 4 files changed, 207 insertions(+), 11 deletions(-) create mode 100644 EN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc diff --git a/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc b/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc index fabd45d4..5cfd62c3 100644 --- a/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc +++ b/CN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc @@ -64,8 +64,8 @@ make -C contrib/pg_track_settings install PG 模式与 Oracle 模式会话下命令相同: [literal, sql] ---- -CREATE EXTENSION pg_track_settings; - +postgres=# CREATE EXTENSION pg_track_settings; +postgres=# SELECT extname, extversion FROM pg_extension WHERE extname = 'pg_track_settings'; extname | extversion -------------------+------------ pg_track_settings | 2.1.2 @@ -126,7 +126,7 @@ postgres=# SELECT * FROM pg_track_settings_diff(now() - interval '10 minutes', n (1 row) ---- -from_exists / to_exists 这两列用来表达参数在两个时间点是否存在。参数被新增时 from_exists 为 false,被移除时 to_exists 为 false —— 这正是前面提到的墓碑记录发挥作用的地方。 +from_exists / to_exists 这两列用来表达参数在两个时间点是否存在。参数被新增时 from_exists 为 false,被移除时 to_exists 为 false。 查看单个参数的完整历史: @@ -179,17 +179,17 @@ postgres=# SELECT * FROM pg_reboot; **关于备份:** 所有历史数据都存在普通表里,因此会被 pg_dump / pg_dumpall 完整备份。这通常是好事,但如果积累了很长的历史又不想带进备份,需要使用 pg_track_settings_reset() 清理。 -**关于时间戳:** 历史表的 ts 列是 timestamptz 类型,存的是绝对时间点,显示时按会话时区换算。跨时区团队查历史时,注意各自会话的 TimeZone 设置可能导致看到的字符串不同,但指向的是同一时刻。 +* **关于时间戳:** 历史表的 ts 列是 timestamptz 类型,存的是绝对时间点,显示时按会话时区换算。跨时区团队查历史时,注意各自会话的 TimeZone 设置可能导致看到的字符串不同,但指向的是同一时刻。 -**关于采集间隔:** 扩展记录的是「发现变更的时刻」,不是「变更实际发生的时刻」。如果两次快照之间某个参数改了又改回来,中间状态会被完全丢失。对配置审计要求严格的场景,应该配合 log_statement = 'ddl' 或专门的审计扩展一起用。 +* **关于采集间隔:** 扩展记录的是「发现变更的时刻」,不是「变更实际发生的时刻」。如果两次快照之间某个参数改了又改回来,中间状态会被完全丢失。对配置审计要求严格的场景,应该配合 log_statement = 'ddl' 或专门的审计扩展一起用。 -**关于权限:** control 文件中 superuser = false,即非超级用户也可以创建该扩展(前提是拥有目标 schema 的权限)。但采集函数需要能读取 pg_settings 和 pg_db_role_setting,实际执行时仍建议用有足够权限的角色。 +* **关于权限:** control 文件中 superuser = false,即非超级用户也可以创建该扩展(前提是拥有目标 schema 的权限)。但采集函数需要能读取 pg_settings 和 pg_db_role_setting,实际执行时仍建议用有足够权限的角色。 -**它不是什么:** 这个扩展只做记录,不做告警,也不会阻止任何配置修改。它是事后排查的工具,不是准入控制。 +* **它不是什么:** 这个扩展只做记录,不做告警,也不会阻止任何配置修改。它是事后排查的工具,不是准入控制。 == 适合场景 -- 多人共同运维、配置变更缺乏统一流程的团队 -- 需要做性能回归分析,想确认「变慢是不是因为改了参数」的 DBA -- 管理大量实例、需要集中掌握配置漂移情况的场景(配合 PoWA) -- 有合规审计要求,需要证明某个时间点配置状态的环境 +* 多人共同运维、配置变更缺乏统一流程的团队 +* 需要做性能回归分析,想确认「变慢是不是因为改了参数」的 DBA +* 管理大量实例、需要集中掌握配置漂移情况的场景(配合 PoWA) +* 有合规审计要求,需要证明某个时间点配置状态的环境 diff --git a/EN/modules/ROOT/nav.adoc b/EN/modules/ROOT/nav.adoc index 1103c116..5a9ceea6 100644 --- a/EN/modules/ROOT/nav.adoc +++ b/EN/modules/ROOT/nav.adoc @@ -76,6 +76,7 @@ *** xref:master/ecosystem_components/zhparser_en.adoc[zhparser] *** xref:master/ecosystem_components/pgbackrest.adoc[pgBackRest] *** xref:master/ecosystem_components/set_user.adoc[set_user] +*** xref:master/ecosystem_components/pg_track_settings.adoc[pg_track_settings] * Monitor and O&M ** xref:master/getting-started/daily_monitoring.adoc[Monitoring] ** xref:master/getting-started/daily_maintenance.adoc[Maintenance] diff --git a/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc b/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc index 4e3270c9..0fee6759 100644 --- a/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc +++ b/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc @@ -42,6 +42,7 @@ IvorySQL, as an advanced open-source database compatible with Oracle and based o |*28*| xref:master/ecosystem_components/zhparser_en.adoc[zhparser] | master branch | PostgreSQL extension for full-text search of Chinese language (Mandarin Chinese). It implements a Chinese language parser base on the | Search engine、keyword extraction |*29*| xref:master/ecosystem_components/pgbackrest.adoc[pgBackRest] | 2.58.0 | pgBackRest is a reliable backup and restore solution for PostgreSQL that seamlessly scales up to the largest databases and workloads | Disaster recovery backup, large database backup, off-site/multi-tier disaster recovery | *30* | xref:master/ecosystem_components/set_user.adoc[set_user] | REL4_2_0 | PostgreSQL security auditing extension with controlled role switching, supporting allowlists, enforced auditing, and blocking of high-risk operations | Controlled role switching, privilege management, audit logging +| *31* | xref:master/ecosystem_components/pg_track_settings.adoc[pg_track_settings] | 2.1.2 | PostgreSQL configuration tracking extension that records configuration change history | Configuration auditing, change tracking |==== These plugins have all been tested and adapted by the IvorySQL team to ensure stable operation in the IvorySQL environment. Users can select appropriate plugins based on business needs to further enhance the capabilities and flexibility of the database system. diff --git a/EN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc b/EN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc new file mode 100644 index 00000000..6ce07396 --- /dev/null +++ b/EN/modules/ROOT/pages/master/ecosystem_components/pg_track_settings.adoc @@ -0,0 +1,194 @@ +:sectnums: +:sectnumlevels: 5 + += pg_track_settings + +== Overview +pg_track_settings is a PostgreSQL extension written in only about 500 lines of PL/pgSQL that tracks changes to the PostgreSQL configuration. + +It provides a function (pg_track_settings_snapshot()) that must be called periodically. On each call, it stores the settings that have changed since the previous call. If PostgreSQL's start time differs from the one recorded previously, it also records the new start time. pg_track_settings is normally used together with a tool such as Cron or PoWA so that sampling happens regularly in production. + +Both IvorySQL's PG mode and its Oracle compatibility mode support pg_track_settings. + +Project page: + +License: PostgreSQL License + +== Function overview + +=== Global parameters + +[options="header"] +|=== +| Function | Purpose +| pg_track_settings_snapshot() | Collect the current configuration and record the differences +| pg_track_settings(timestamptz) | Return the full configuration as of the given point in time; if the argument is omitted, the current time is used +| pg_track_settings_diff(timestamptz, timestamptz) | Return every parameter that changed between the two points in time +| pg_track_settings_log(text) | Return the complete change history of a single given parameter +|=== + +=== Database-level / role-level override parameters + +[options="header"] +|=== +| Function | Purpose +| pg_track_db_role_settings(timestamptz) | All override settings as of the given point in time +| pg_track_db_role_settings_diff(timestamptz, timestamptz) | Override settings that changed between the two points in time +| pg_track_db_role_settings_log(text) | Change history of a single override parameter +|=== + +=== Maintenance + +[options="header"] +|=== +| Function | Purpose +| pg_track_settings_reset() | Clear all history records +|=== + +== Installation and enablement + +=== Building from source + +Build and install from source: +[literal, bash] +---- +# Build and install pg_track_settings +cd ivorysql +git clone https://github.com/rjuju/pg_track_settings.git contrib/pg_track_settings +make -C contrib/pg_track_settings install +---- + +=== Installing the extension + +The commands are the same in PG mode and Oracle mode sessions: +[literal, sql] +---- +postgres=# CREATE EXTENSION pg_track_settings; +postgres=# SELECT extname, extversion FROM pg_extension WHERE extname = 'pg_track_settings'; + extname | extversion +-------------------+------------ + pg_track_settings | 2.1.2 +---- + +== Usage walkthrough + +[TIP] +==== +The output below is illustrative; it is meant to show the form in which each function returns its results. +==== + +First take a snapshot to establish a baseline: + +[literal, sql] +---- +postgres=# SELECT pg_track_settings_snapshot(); + pg_track_settings_snapshot +---------------------------- + t +(1 row) +---- + +At this point the history table already holds a first batch of records: + +[literal, sql] +---- +postgres=# SELECT DISTINCT ts FROM pg_track_settings_history; + ts +------------------------------- + 2026-09-08 10:00:37.449846+08 +(1 row) +---- + +Now suppose someone changes a setting and reloads: + +[literal, sql] +---- +postgres=# ALTER SYSTEM SET work_mem = '32MB'; +postgres=# SELECT pg_reload_conf(); +---- + +Take another snapshot, then look at the changes over that period: + +[TIP] +==== +In Oracle compatibility mode you must use make_interval(mins => 10) instead of interval '10 minutes', otherwise an error is raised. +==== + +[literal, sql] +---- +postgres=# SELECT pg_track_settings_snapshot(); + +postgres=# SELECT * FROM pg_track_settings_diff(now() - interval '10 minutes', now()); + name | from_setting | from_exists | to_setting | to_exists +----------+--------------+-------------+------------+----------- + work_mem | 4096 | t | 32768 | t +(1 row) +---- + +The from_exists / to_exists columns express whether the parameter existed at each of the two points in time. When a parameter is added, from_exists is false; when it is removed, to_exists is false. + +View the complete history of a single parameter: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_track_settings_log('work_mem'); + ts | name | setting_exists | setting +-------------------------------+----------+----------------+--------- + 2026-09-08 10:06:42.581682+08 | work_mem | t | 32768 + 2026-09-08 10:00:37.449846+08 | work_mem | t | 4096 +(2 rows) +---- + +Reconstruct the full configuration as of any point in time: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_track_settings('2026-09-08 10:03:00'); + name | setting +------------------------------+--------- + [...] + checkpoint_completion_target | 0.9 + checkpoint_timeout | 300 + work_mem | 4096 + [...] +---- + +View the history of override parameters: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_track_db_role_settings_log('statement_timeout'); + ts | dbname | rolname | name | setting_exists | setting +-------------------------------+----------+----------+-------------------+----------------+--------- + 2026-09-08 11:15:03.112094+08 | appdb | | statement_timeout | t | 30s +---- + +View the instance restart history: + +[literal, sql] +---- +postgres=# SELECT * FROM pg_reboot; + ts +------------------------------- + 2026-09-08 09:39:43.609195+08 +(1 row) +---- + +== Things to be aware of + +**About backups:** All historical data is stored in ordinary tables, so it is backed up in full by pg_dump / pg_dumpall. This is usually a good thing, but if a long history has accumulated and you do not want it included in the backup, use pg_track_settings_reset() to clean it up. + +* **About timestamps:** The ts column of the history tables is of type timestamptz, so it stores an absolute point in time and is converted to the session time zone for display. When a team spanning multiple time zones queries the history, note that different session TimeZone settings may produce different displayed strings, even though they refer to the same instant. + +* **About the sampling interval:** The extension records the moment a change was *discovered*, not the moment the change actually *occurred*. If a parameter is changed and then changed back between two snapshots, the intermediate state is lost entirely. In scenarios with strict configuration-audit requirements, it should be used together with log_statement = 'ddl' or a dedicated audit extension. + +* **About privileges:** The control file sets superuser = false, meaning non-superusers can also create the extension (provided they have privileges on the target schema). However, the collection function needs to be able to read pg_settings and pg_db_role_setting, so in practice it is still advisable to run it as a role with sufficient privileges. + +* **What it is not:** This extension only records; it does not alert, and it does not prevent any configuration change. It is a tool for after-the-fact investigation, not admission control. + +== Suitable scenarios + +* Teams where several people share operational duties and configuration changes lack a unified process +* DBAs performing performance regression analysis who want to confirm whether "it got slower" was caused by a parameter change +* Environments managing a large number of instances where configuration drift needs to be tracked centrally (together with PoWA) +* Environments with compliance audit requirements that need to prove the configuration state at a given point in time