主頁 > 資料庫 > PostgreSQL VACUUM 之深入淺出 (二)

PostgreSQL VACUUM 之深入淺出 (二)

2022-02-26 08:48:45 資料庫

AUTOVACUUM

AUTOVACUUM 簡介

PostgreSQL 提供了 AUTOVACUUM 的機制,

autovacuum 不僅會自動進行 VACUUM,也會自動進行 ANALYZE,以分析統計資訊用于執行計劃,

在 postgresql.conf 中,autovacuum 引數已默認打開,

autovacuum = on

autovacuum 打開后,會有一個 autovacuum launcher 行程

$ ps -ef|grep postgres|grep autovacuum|grep -v grep
postgres 28398 28392  0 Nov13 ?        00:00:19 postgres: autovacuum launcher  

pg_stat_activity 也可以看到 backend_type 為 autovacuum launcher 的連接:

psql -d alvindb -U postgres
alvindb=# \x
Expanded display is on.
alvindb=# SELECT * FROM pg_stat_activity WHERE backend_type = 'autovacuum launcher';
-[ RECORD 1 ]----+------------------------------
datid            | 
datname          | 
pid              | 28398
usesysid         | 
usename          | 
application_name | 
client_addr      | 
client_hostname  | 
client_port      | 
backend_start    | 2021-11-13 23:18:00.406618+08
xact_start       | 
query_start      | 
state_change     | 
wait_event_type  | Activity
wait_event       | AutoVacuumMain
state            | 
backend_xid      | 
backend_xmin     | 
query            | 
backend_type     | autovacuum launcher

那么 AUTOVACUUM 多久運行一次?

autovacuum launcher 會每隔 autovacuum_naptime ,創建 autovacuum worker,檢查是否需要做 autovacuum,

psql -d alvindb -U postgres
alvindb=# SELECT * FROM pg_stat_activity WHERE backend_type = 'autovacuum worker';
-[ RECORD 1 ]----+------------------------------
datid            | 13220
datname          | postgres
pid              | 32457
usesysid         | 
usename          | 
application_name | 
client_addr      | 
client_hostname  | 
client_port      | 
backend_start    | 2021-11-06 23:32:53.880281+08
xact_start       | 
query_start      | 
state_change     | 
wait_event_type  | 
wait_event       | 
state            | 
backend_xid      | 
backend_xmin     | 
query            | 
backend_type     | autovacuum worker

autovacuum_naptime 默認為 1min:

#autovacuum_naptime = 1min		# time between autovacuum runs

autovacuum 又是根據什么標準決定是否進行 VACUUM 和 ANALYZE 呢?

當 autovacuum worker 檢查到,

dead tuples 大于 vacuum threshold 時,會自動進行 VACUUM,

vacuum threshold 公式如下:

vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuples

增刪改的行資料大于 analyze threshold 時,會自動進行 ANALYZE,

analyze threshold 公式如下:

analyze threshold = analyze base threshold + analyze scale factor * number of tuples

對應 postgresql.conf 中相關引數如下:

#autovacuum_vacuum_threshold = 50       # min number of row updates before vacuum
#autovacuum_analyze_threshold = 50      # min number of row updates before analyze
#autovacuum_vacuum_scale_factor = 0.2   # fraction of table size before vacuum
#autovacuum_analyze_scale_factor = 0.1  # fraction of table size before analyze

dead tuples 為 pg_stat_user_tables.n_dead_tup(Estimated number of dead rows)

alvindb=> SELECT * FROM pg_stat_user_tables WHERE schemaname = 'alvin' AND relname = 'tb_test_vacuum';
-[ RECORD 1 ]-------+---------------
relid               | 37409
schemaname          | alvin
relname             | tb_test_vacuum
seq_scan            | 2
seq_tup_read        | 0
idx_scan            | 0
idx_tup_fetch       | 0
n_tup_ins           | 0
n_tup_upd           | 0
n_tup_del           | 0
n_tup_hot_upd       | 0
n_live_tup          | 0
n_dead_tup          | 0
n_mod_since_analyze | 0
last_vacuum         | 
last_autovacuum     | 
last_analyze        | 
last_autoanalyze    | 
vacuum_count        | 0
autovacuum_count    | 0
analyze_count       | 0
autoanalyze_count   | 0

那么 number of tuples 是哪個列的值?是 pg_stat_user_tables.n_live_tup(Estimate number of live rows)?還是實際的 count 值?

其實是 pg_class.reltuples (Estimate number of live rows in the table used by the planner),

alvindb=> SELECT u.schemaname,u.relname,c.reltuples,u.n_live_tup,u.n_mod_since_analyze,u.n_dead_tup,u.last_autoanalyze,u.last_autovacuum
FROM
    pg_stat_user_tables u, pg_class c, pg_namespace n
WHERE n.oid = c.relnamespace
    AND c.relname = u.relname
    AND n.nspname = u.schemaname
    AND u.schemaname = 'alvin'
    AND u.relname = 'tb_test_vacuum'
-[ RECORD 1 ]-------+---------------
schemaname          | alvin
relname             | tb_test_vacuum
reltuples           | 0
n_live_tup          | 0
n_mod_since_analyze | 0
n_dead_tup          | 0
last_autoanalyze    | 
last_autovacuum     | 

所以 AUTO VACUUM 具體公式如下:

pg_stat_user_tables.n_dead_tup > autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor * pg_class.reltuples

同理,AUTO ANALYZE 具體公式如下:

pg_stat_user_tables.n_mod_since_analyze > autovacuum_analyze_threshold + autovacuum_analyze_scale_factor * pg_class.reltuples

精準觸發 AUTOVACUUM

下面實測一下 autovacuum,為了測驗方便,autovacuum_naptime 臨時修改為 5s,這樣觸發了臨界條件,只需要等 5s 就能看到效果,而不是等 1min,

修改引數如下:

autovacuum_naptime = 5s
autovacuum_vacuum_threshold = 100       # min number of row updates before vacuum
autovacuum_analyze_threshold = 100      # min number of row updates before analyze
autovacuum_vacuum_scale_factor = 0.2    # fraction of table size before vacuum
autovacuum_analyze_scale_factor = 0.1   # fraction of table size before analyze

接下來通過一步一步測驗,精準觸發 autovacuum,

為了方便測驗,通過如下 AUTOVACUUM 計算 SQL 計算需要洗掉或修改的資料行數,

alvindb=> WITH v AS (
  SELECT * FROM
    (SELECT setting AS autovacuum_vacuum_scale_factor FROM pg_settings WHERE name = 'autovacuum_vacuum_scale_factor') vsf,
    (SELECT setting AS autovacuum_vacuum_threshold FROM pg_settings WHERE name = 'autovacuum_vacuum_threshold') vth,
    (SELECT setting AS autovacuum_analyze_scale_factor FROM pg_settings WHERE name = 'autovacuum_analyze_scale_factor') asf,
    (SELECT setting AS autovacuum_analyze_threshold FROM pg_settings WHERE name = 'autovacuum_analyze_threshold') ath
),
t AS (
    SELECT
        c.reltuples,u.*
    FROM
        pg_stat_user_tables u, pg_class c, pg_namespace n
    WHERE n.oid = c.relnamespace
        AND c.relname = u.relname
        AND n.nspname = u.schemaname
        AND u.schemaname = 'alvin'
        AND u.relname = 'tb_test_vacuum'
)
SELECT
    schemaname,
    relname,
    autovacuum_vacuum_scale_factor,
    autovacuum_vacuum_threshold,
    autovacuum_analyze_scale_factor,
    autovacuum_analyze_threshold,
    n_live_tup,
    reltuples,
    autovacuum_analyze_trigger,
    n_mod_since_analyze,
    autovacuum_analyze_trigger - n_mod_since_analyze AS rows_to_mod_before_auto_analyze,
    last_autoanalyze,
    autovacuum_vacuum_trigger,
    n_dead_tup,
    autovacuum_vacuum_trigger - n_dead_tup AS rows_to_delete_before_auto_vacuum,
    last_autovacuum
FROM (
    SELECT
        schemaname,
        relname,
        autovacuum_vacuum_scale_factor,
        autovacuum_vacuum_threshold,
        autovacuum_analyze_scale_factor,
        autovacuum_analyze_threshold,
        floor(autovacuum_analyze_scale_factor::numeric * reltuples) + 1 + autovacuum_analyze_threshold::int AS autovacuum_analyze_trigger,
        floor(autovacuum_vacuum_scale_factor::numeric * reltuples) + 1 + autovacuum_vacuum_threshold::int AS autovacuum_vacuum_trigger,
        reltuples,
        n_live_tup,
        n_dead_tup,
        n_mod_since_analyze,
        last_autoanalyze,
        last_autovacuum
    FROM
        v,
        t) a;
-[ RECORD 1 ]---------------------+---------------
schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 0
reltuples                         | 0
autovacuum_analyze_trigger        | 101
n_mod_since_analyze               | 0
rows_to_mod_before_auto_analyze   | 101
last_autoanalyze                  | 
autovacuum_vacuum_trigger         | 101
n_dead_tup                        | 0
rows_to_delete_before_auto_vacuum | 101
last_autovacuum                   | 

根據計算公式,

pg_stat_user_tables.n_mod_since_analyze > 100 + 0.1 * 0

即當修改的行數大于 100,即為 101 時,將觸發 AUTO ANALYZE,

先插入 100 行資料,

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:45:57.669183+08
(1 row)
alvindb=> INSERT INTO tb_test_vacuum(test_num) SELECT gid FROM generate_series(1,100,1) gid;
INSERT 0 100

此時,通過如下計算可以看到,再更新 1 行,將觸發 AUTO ANALYZE,

schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 100
reltuples                         | 0
autovacuum_analyze_trigger        | 101
n_mod_since_analyze               | 100
rows_to_mod_before_auto_analyze   | 1
last_autoanalyze                  | 
autovacuum_vacuum_trigger         | 101
n_dead_tup                        | 0
rows_to_delete_before_auto_vacuum | 101
last_autovacuum                   | 

此時,統計資訊為空:

alvindb=> SELECT * FROM pg_stats WHERE schemaname = 'alvin' AND tablename = 'tb_test_vacuum';
(0 rows)

現在插入最后一條資料,

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:46:31.034422+08
(1 row)
alvindb=> INSERT INTO tb_test_vacuum(test_num) SELECT gid FROM generate_series(101,101,1) gid;
INSERT 0 1

執行 AUTOVACUUM 計算 SQL, 可以看到,已觸發 AUTO ANALYZE:

schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 101
reltuples                         | 101
autovacuum_analyze_trigger        | 111
n_mod_since_analyze               | 0
rows_to_mod_before_auto_analyze   | 111
last_autoanalyze                  | 2021-11-06 20:46:39.88796+08
autovacuum_vacuum_trigger         | 121
n_dead_tup                        | 0
rows_to_delete_before_auto_vacuum | 121
last_autovacuum                   | 

可以看到表 tb_test_vacuum 統計資訊已更新:

alvindb=> SELECT * FROM pg_stats WHERE schemaname = 'alvin' AND tablename = 'tb_test_vacuum';

查看 PostgreSQL 日志,可以看到

[    2021-11-06 20:46:39.887 CST 6816 6186792f.1aa0 1 3/173948 13179359]LOG:  automatic analyze of table "alvindb.alvin.tb_test_vacuum" system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s

PostgreSQL 日志中是否記錄 AUTOVACUUM 由引數 log_autovacuum_min_duration 控制,默認關閉,

#log_autovacuum_min_duration = -1	# -1 disables, 0 logs all actions and
					# their durations, > 0 logs only
					# actions running at least this number
					# of milliseconds.

可將該引數改為 0,即記錄所有的 AUTOVACUUM 操作,

log_autovacuum_min_duration = 0

AUTOVACUUM 計算 SQL 的執行結果得知,再修改 111 行將觸發 AUTO ANALYZE,

rows_to_mod_before_auto_analyze   | 111
rows_to_delete_before_auto_vacuum | 121

先修改 110 行,并 sleep 6s,

alvindb=> SELECT clock_timestamp();
       clock_timestamp        
------------------------------
 2021-11-06 20:47:30.75553+08
(1 row)
alvindb=> INSERT INTO tb_test_vacuum(test_num) SELECT gid FROM generate_series(102,111,1) gid;
INSERT 0 10
alvindb=> UPDATE tb_test_vacuum SET test_num = test_num WHERE test_num <= 100;
UPDATE 100
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:47:43.465651+08
(1 row)

AUTOVACUUM 計算 SQL 的執行結果得知,修改后 110 行并 sleep 6s (前面已將 autovacuum_naptime 設定成了 5s)后,AUTO ANALYZE 并未觸發,

schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 111
reltuples                         | 101
autovacuum_analyze_trigger        | 111
n_mod_since_analyze               | 110
rows_to_mod_before_auto_analyze   | 1
last_autoanalyze                  | 2021-11-06 20:46:39.88796+08
autovacuum_vacuum_trigger         | 121
n_dead_tup                        | 100
rows_to_delete_before_auto_vacuum | 21
last_autovacuum                   | 

再修改 1 行預計將觸發 AUTO ANALYZE,此時洗掉一行:

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:47:55.746411+08
(1 row)
alvindb=> DELETE FROM tb_test_vacuum WHERE test_id = 111;
DELETE 1
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:48:01.796389+08
(1 row)

AUTOVACUUM 計算 SQL 的查詢結果中的 last_autoanalyze 得知,已精準觸發 AUTO ANALYZE,

并且從 rows_to_delete_before_auto_vacuum 得知,預計洗掉 22 行后,將觸發 AUTO VACUUM,

schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 110
reltuples                         | 110
autovacuum_analyze_trigger        | 112
n_mod_since_analyze               | 0
rows_to_mod_before_auto_analyze   | 112
last_autoanalyze                  | 2021-11-06 20:48:04.928899+08
autovacuum_vacuum_trigger         | 123
n_dead_tup                        | 101
rows_to_delete_before_auto_vacuum | 22
last_autovacuum                   | 

先洗掉 (UPDATE = DELETE + INSERT) 21 行:

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:48:32.313706+08
(1 row)

alvindb=> UPDATE tb_test_vacuum SET test_num = test_num WHERE test_num <= 21;
UPDATE 21
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:48:38.454997+08
(1 row)

AUTOVACUUM 計算 SQL 的查詢結果中的 last_autovacuum 得知,還未觸發 AUTO VACUUM,

并且從 rows_to_delete_before_auto_vacuum 得知,預計洗掉 1 行后,將觸發 AUTO VACUUM,

schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 110
reltuples                         | 110
autovacuum_analyze_trigger        | 112
n_mod_since_analyze               | 21
rows_to_mod_before_auto_analyze   | 91
last_autoanalyze                  | 2021-11-06 20:48:04.928899+08
autovacuum_vacuum_trigger         | 123
n_dead_tup                        | 122
rows_to_delete_before_auto_vacuum | 1
last_autovacuum                   | 

此時洗掉一行

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:48:39.174009+08
(1 row)

alvindb=> DELETE FROM tb_test_vacuum WHERE test_id = 110;
DELETE 1
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 20:48:45.213537+08
(1 row)

AUTOVACUUM 計算 SQL 的查詢結果中的 last_autovacuum 得知,已精準觸發 AUTO VACUUM!

schemaname                        | alvin
relname                           | tb_test_vacuum
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 100
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 100
n_live_tup                        | 109
reltuples                         | 109
autovacuum_analyze_trigger        | 111
n_mod_since_analyze               | 22
rows_to_mod_before_auto_analyze   | 89
last_autoanalyze                  | 2021-11-06 20:48:04.928899+08
autovacuum_vacuum_trigger         | 122
n_dead_tup                        | 0
rows_to_delete_before_auto_vacuum | 122
last_autovacuum                   | 2021-11-06 20:48:49.914345+08

查看 PostgreSQL 日志,可以看到

[    2021-11-06 20:48:49.914 CST 7207 618679b1.1c27 1 3/174162 0]LOG:  automatic vacuum of table "alvindb.alvin.tb_test_vacuum": index scans: 1
	pages: 0 removed, 1 remain, 0 skipped due to pins, 0 skipped frozen
	tuples: 123 removed, 109 remain, 0 are dead but not yet removable, oldest xmin: 13179371
	buffer usage: 59 hits, 4 misses, 4 dirtied
	avg read rate: 121.832 MB/s, avg write rate: 121.832 MB/s
	system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
	buffer usage: 59 hits, 4 misses, 4 dirtied
	avg read rate: 121.832 MB/s, avg write rate: 121.832 MB/s
	system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s

那么問題來了,autovacuum_vacuum_scale_factor 為 0.2 對于所有的表都合適嗎?1 億資料量的表有 2000 萬 dead tuples 以上才會觸發 AUTO VACUUM,這意味著表越大越不容易觸發 AUTO VACUUM,怎么可以解決這個問題呢?

精準觸發表級 AUTOVACUUM

可以根據需要,在表上設定合理的 autovacuum_vacuum_scale_factor,對于大表,可以設定小點的 autovacuum_vacuum_scale_factor,如 0.1,

下面帶你一步一步設定并精確觸發表級的 AUTO ANALYZE 和 AUTO VACUUM,

這次將采用大一點的資料量進行測驗,考慮到手動創建表,插入資料等比較麻煩,接下來測驗利用 PostgreSQL 自帶的工具 pgbench,

使用 pgbench 創建 10 萬行資料的測驗表:

$ pgbench -i alvindb
dropping old tables...
creating tables...
generating data...
100000 of 100000 tuples (100%) done (elapsed 0.38 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done.

修改表級引數:

alvindb=> ALTER TABLE pgbench_accounts SET (autovacuum_vacuum_scale_factor = 0.1, autovacuum_vacuum_threshold = 2000);
ALTER TABLE
alvindb=> ALTER TABLE pgbench_accounts SET (autovacuum_analyze_scale_factor = 0.05, autovacuum_analyze_threshold = 2000);
ALTER TABLE

按照之前 AUTOVACUUM 計算 SQL ,可知要修改 11001 行才會觸發 AUTO ANALYZE, 要有約 21001 個 dead tuples 才會觸發 AUTO VACUUM,

schemaname                        | public
relname                           | pgbench_accounts
autovacuum_vacuum_scale_factor    | 0.2
autovacuum_vacuum_threshold       | 1000
autovacuum_analyze_scale_factor   | 0.1
autovacuum_analyze_threshold      | 1000
n_live_tup                        | 100000
reltuples                         | 100000
autovacuum_analyze_trigger        | 11001
n_mod_since_analyze               | 0
rows_to_mod_before_auto_analyze   | 11001
last_autoanalyze                  | 
autovacuum_vacuum_trigger         | 21001
n_dead_tup                        | 0
rows_to_delete_before_auto_vacuum | 21001
last_autovacuum                   | 

現在設定了表級的引數以后,從如下 表級 AUTOVACUUM 計算 SQL ,可知修改 7001 行就可以觸發 AUTO ANALYZE, 有約 12001 個 dead tuples 就可以觸發 AUTO VACUUM,更重要的是,表級的 AUTOVACUUM 引數不會對其他表產生影響,只對已設定的表有效,也可以對不同大小的表設定不同的引數,還可以隨時調整!

表級 AUTOVACUUM 計算 SQL

alvindb=> WITH v AS (
SELECT (SELECT split_part(x, '=', 2) FROM unnest(c.reloptions) q (x) WHERE x ~ '^autovacuum_vacuum_scale_factor=' ) as autovacuum_vacuum_
scale_factor,
    (SELECT split_part(x, '=', 2) FROM unnest(c.reloptions) q (x) WHERE x ~ '^autovacuum_vacuum_threshold=' ) as autovacuum_vacuum_thresh
old,
    (SELECT split_part(x, '=', 2) FROM unnest(c.reloptions) q (x) WHERE x ~ '^autovacuum_analyze_scale_factor=' ) as autovacuum_analyze_s
cale_factor,
    (SELECT split_part(x, '=', 2) FROM unnest(c.reloptions) q (x) WHERE x ~ '^autovacuum_analyze_threshold=' ) as autovacuum_analyze_thre
shold
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname IN ('public')
AND c.relname = 'pgbench_accounts'
),
t AS (
    SELECT
        c.reltuples,u.*
    FROM
        pg_stat_user_tables u, pg_class c, pg_namespace n
    WHERE n.oid = c.relnamespace
        AND c.relname = u.relname
        AND n.nspname = u.schemaname
        AND u.schemaname = 'public'
        AND u.relname = 'pgbench_accounts'
)
SELECT
    schemaname,
    relname,
    autovacuum_vacuum_scale_factor,
    autovacuum_vacuum_threshold,
    autovacuum_analyze_scale_factor,
    autovacuum_analyze_threshold,
    n_live_tup,
    reltuples,
    autovacuum_analyze_trigger,
    n_mod_since_analyze,
    autovacuum_analyze_trigger - n_mod_since_analyze AS rows_to_mod_before_analyze,
    last_autoanalyze,
    autovacuum_vacuum_trigger,
    n_dead_tup,
    autovacuum_vacuum_trigger - n_dead_tup AS rows_to_delete_before_vacuum,
    last_autovacuum
FROM (
    SELECT
        schemaname,
        relname,
        autovacuum_vacuum_scale_factor,
        autovacuum_vacuum_threshold,
        autovacuum_analyze_scale_factor,
        autovacuum_analyze_threshold,
        floor(autovacuum_analyze_scale_factor::numeric * reltuples) + 1 + autovacuum_analyze_threshold::int AS autovacuum_analyze_trigger,
        floor(autovacuum_vacuum_scale_factor::numeric * reltuples) + 1 + autovacuum_vacuum_threshold::int AS autovacuum_vacuum_trigger,
        reltuples,
        n_live_tup,
        n_dead_tup,
        n_mod_since_analyze,
        last_autoanalyze,
        last_autovacuum
    FROM
        v,
        t) a;
-[ RECORD 1 ]-------------------+-----------------
schemaname                      | public
relname                         | pgbench_accounts
autovacuum_vacuum_scale_factor  | 0.1
autovacuum_vacuum_threshold     | 2000
autovacuum_analyze_scale_factor | 0.05
autovacuum_analyze_threshold    | 2000
n_live_tup                      | 100000
reltuples                       | 100000
autovacuum_analyze_trigger      | 7001
n_mod_since_analyze             | 0
rows_to_mod_before_analyze      | 7001
last_autoanalyze                | 
autovacuum_vacuum_trigger       | 12001
n_dead_tup                      | 0
rows_to_delete_before_vacuum    | 12001
last_autovacuum                 | 

現在已預測到要修改的行數,接下來一步一步來觸發一下表級的 AUTO ANALYZE 和 AUTO VACUUM,

先洗掉 7000 行資料:

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:03.252622+08
(1 row)
alvindb=> DELETE FROM pgbench_accounts WHERE aid<=7000;
DELETE 7000
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:09.363536+08
(1 row)

根據表級 AUTOVACUUM 計算 SQL 執行結果的 rows_to_mod_before_analyze 得知,再修改 1 行將觸發 AUTO ANALYZE:

schemaname                      | public
relname                         | pgbench_accounts
autovacuum_vacuum_scale_factor  | 0.1
autovacuum_vacuum_threshold     | 2000
autovacuum_analyze_scale_factor | 0.05
autovacuum_analyze_threshold    | 2000
n_live_tup                      | 93000
reltuples                       | 100000
autovacuum_analyze_trigger      | 7001
n_mod_since_analyze             | 7000
rows_to_mod_before_analyze      | 1
last_autoanalyze                | 
autovacuum_vacuum_trigger       | 12001
n_dead_tup                      | 7000
rows_to_delete_before_vacuum    | 5001
last_autovacuum                 | 

再修改 1 行:

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:30.649717+08
(1 row)
alvindb=> UPDATE pgbench_accounts SET bid = bid WHERE aid=7001;
UPDATE 1
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:36.705928+08
(1 row)

根據表級 AUTOVACUUM 計算 SQL 執行結果的 last_autoanalyze 得知,已精準觸發 AUTO ANALYZE!

schemaname                      | public
relname                         | pgbench_accounts
autovacuum_vacuum_scale_factor  | 0.1
autovacuum_vacuum_threshold     | 2000
autovacuum_analyze_scale_factor | 0.05
autovacuum_analyze_threshold    | 2000
n_live_tup                      | 93000
reltuples                       | 93000
autovacuum_analyze_trigger      | 6651
n_mod_since_analyze             | 0
rows_to_mod_before_analyze      | 6651
last_autoanalyze                | 2021-11-06 23:33:40.87317+08
autovacuum_vacuum_trigger       | 11301
n_dead_tup                      | 7001
rows_to_delete_before_vacuum    | 4300
last_autovacuum                 | 

從 PostgreSQL 日志中也可以看到 AUTO ANALYZE 被觸發了:

[    2021-11-06 23:33:40.873 CST 32646 6186a054.7f86 1 6/1393 13179750]LOG:  automatic analyze of table "alvindb.public.pgbench_accounts" syst
em usage: CPU: user: 0.04 s, system: 0.03 s, elapsed: 0.11 s

并且,根據 rows_to_delete_before_vacuum 得知,再洗掉 4300 行就可以觸發 AUTO VACUUM,

接下來先洗掉 4299 行,以測驗臨界值:

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:43.867176+08
(1 row)
alvindb=> UPDATE pgbench_accounts SET bid = bid WHERE aid>=95702;
UPDATE 4299
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:50.016447+08
(1 row)

autovacuum_naptime 為 5s,此時并未觸發 AUTO VACUUM,

schemaname                      | public
relname                         | pgbench_accounts
autovacuum_vacuum_scale_factor  | 0.1
autovacuum_vacuum_threshold     | 2000
autovacuum_analyze_scale_factor | 0.05
autovacuum_analyze_threshold    | 2000
n_live_tup                      | 93000
reltuples                       | 93000
autovacuum_analyze_trigger      | 6651
n_mod_since_analyze             | 4299
rows_to_mod_before_analyze      | 2352
last_autoanalyze                | 2021-11-06 23:33:40.87317+08
autovacuum_vacuum_trigger       | 11301
n_dead_tup                      | 11300
rows_to_delete_before_vacuum    | 1
last_autovacuum                 | 

再洗掉 (UPDATE = DELETE + INSERT) 1 行 :

alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:53.326483+08
(1 row)
alvindb=> UPDATE pgbench_accounts SET bid = bid WHERE aid=7002;
UPDATE 1
alvindb=> SELECT pg_sleep(6);
 pg_sleep 
----------
 
(1 row)
alvindb=> SELECT clock_timestamp();
        clock_timestamp        
-------------------------------
 2021-11-06 23:33:59.439375+08
(1 row)

從如下結果中的 last_autovacuum 得知,此時已精確觸發 AUTO VACUUM!

schemaname                      | public
relname                         | pgbench_accounts
autovacuum_vacuum_scale_factor  | 0.1
autovacuum_vacuum_threshold     | 2000
autovacuum_analyze_scale_factor | 0.05
autovacuum_analyze_threshold    | 2000
n_live_tup                      | 93000
reltuples                       | 93000
autovacuum_analyze_trigger      | 6651
n_mod_since_analyze             | 4300
rows_to_mod_before_analyze      | 2351
last_autoanalyze                | 2021-11-06 23:33:40.87317+08
autovacuum_vacuum_trigger       | 11301
n_dead_tup                      | 0
rows_to_delete_before_vacuum    | 11301
last_autovacuum                 | 2021-11-06 23:34:00.956936+08

從 PostgreSQL 日志中也可以看到 AUTO VACUUM 被觸發了:

[    2021-11-06 23:34:00.956 CST 32710 6186a068.7fc6 1 6/1455 0]LOG:  automatic vacuum of table "alvindb.public.pgbench_accounts": index scans
: 1
        pages: 0 removed, 421 remain, 0 skipped due to pins, 0 skipped frozen
        tuples: 2 removed, 93000 remain, 0 are dead but not yet removable, oldest xmin: 13179755
        buffer usage: 967 hits, 60 misses, 7 dirtied
        avg read rate: 10.067 MB/s, avg write rate: 1.174 MB/s
        system usage: CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.18 s

公眾號

關注 DBA Daily 公眾號,第一時間收到文章的更新,
通過一線 DBA 的日常作業,學習實用資料庫技術干貨!

公眾號優質文章推薦

PostgreSQL VACUUM 之深入淺出

華山論劍之 PostgreSQL sequence

[PG Upgrade Series] Extract Epoch Trap

[PG Upgrade Series] Toast Dump Error

GitLab supports only PostgreSQL now

MySQL or PostgreSQL?

PostgreSQL hstore Insight

ReIndex 失敗原因調查

PG 資料匯入 Hive 亂碼問題調查

PostGIS 擴展創建失敗原因調查

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/433184.html

標籤:PostgreSQL

上一篇:如何從Struts2中的屬性檔案中獲取源路徑和替代文本值以插入影像?在Struts1中使用了altKey和srcKey

下一篇:容器化 | 在 KubeSphere 中部署 MySQL 集群

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more