備庫是否有自己的統計資訊?(續)

資料庫工作筆記發表於2023-11-23

前言

今天③群裡有位群友提了這樣一個問題,引起了我的思考

問個小白問題,pg_stat_all_indexes 的資訊,重啟或主備切換後資料是重新收集的嗎?

我直接拍腦袋不假思索就回復了 "reset了"。然後這位群友就順著回覆我

近期有主備切換,那依據裡面的資訊來判斷索引是否有使用是不可靠的

我後面轉念一想,才發現這個回覆是錯誤的,不嚴謹,儘早寫出來加深印象,以免遺忘。

分析

簡單驗證一下,主庫上建個表並使用索引掃描

postgres=# create table tbl1(id int);
CREATE TABLE
postgres=# insert into tbl1 values(generate_series(1,100000));
INSERT 0 100000
postgres=# create index on tbl1(id);
CREATE INDEX
postgres=# explain analyze select * from tbl1 where id = 99;
                                                      QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
 Index Only Scan using tbl1_id_idx on tbl1  (cost=0.29..4.31 rows=1 width=4) (actual time=0.026..0.028 rows=1 loops=1)
   Index Cond: (id = 99)
   Heap Fetches: 0
 Planning Time0.100 ms
 Execution Time0.053 ms
(5 rows)

postgres=# select * from pg_stat_all_indexes where relname = 'tbl1';
-[ RECORD 1 ]-+------------------------------
relid         | 58029
indexrelid    | 58032
schemaname    | public
relname       | tbl1
indexrelname  | tbl1_id_idx
idx_scan      | 1
last_idx_scan | 2023-11-22 22:38:59.827939+08
idx_tup_read  | 1
idx_tup_fetch | 0

此處的 last_idx_scan 是 16 引入的新特性,可以讓我們獲取最近未使用過的索引列表,在以前的版本是無法直接查詢在給定時間段內是否使用過某個索引的。

再去備庫上檢視一下

postgres=# select pg_is_in_recovery(),* from pg_stat_all_indexes where relname = 'tbl1';
-[ RECORD 1 ]-----+------------
pg_is_in_recovery | t
relid             | 58029
indexrelid        | 58032
schemaname        | public
relname           | tbl1
indexrelname      | tbl1_id_idx
idx_scan          | 0
last_idx_scan     | 
idx_tup_read      | 0
idx_tup_fetch     | 0

可以看到,資料並不一致,主庫上使用索引故 idx_scan 為 1,備庫上為 0。其實仔細思考?一下也不難理解:備庫是可以承載查詢的,因此備庫有一套"獨立"的統計資訊並不奇怪。同理,pg_stat_database、pg_stat_bgwriter、pg_stat_user_functions等等,主備的資料都可以不一致。

但是有個較為特別的"檢視",沒錯——pg_stat_all_tables,我之前也曾寫過一篇有關備庫統計資訊的文章 備庫是否有自己的統計資訊?裡面也提及過相關底層知識:

pg_stat_all_tables 並不是一個普通的表,透過 \d+ 可以看到其定義,它只是一個檢視,本質上就是一系列函式,有關表上各個維度的計數器。這些函式是與 stats collector 打交道的,每個後端程式事務提交/回滾時會發訊息給程式 stats collector,stats collector 會彙總這份資訊並記錄到檔案中,因此 stats collector 使用的是自己的檔案,而不是普通的表進行儲存,因此該資料不會被複制到備庫。另外一個細節是 pg_basebackup 在複製的時候會忽略 pg_stat_tmp/pg_stat 目錄下的內容 (15以前的版本)。

因此,這裡就會有個很微妙的問題:試想一下,如果發生了主從切換,舊主上的這部分統計資訊就"丟失"了,只有當新主上發生了新的活動才會彙總到 pg_stat_all_tables 中,那麼假如原來舊主上有個表即將達到 vacuum/analyze 的觸發閾值,但是由於主從切換,那麼這個表就會"膨脹",亦或是使用陳舊過時的統計資訊,需要等到下一次觸發閾值才會進行清理/分析,所以這也是一個潛在的微妙問題。

至於另外一個 pg_statistic,由於是統計資訊表,但它是一個普通的表,因此也會被正常複製到備庫,這一點無需擔心主從切換後統計資訊丟失。

pg_stat_reset

那麼我當時為什麼會拍腦袋回覆"reset"呢?PostgreSQL 提供了一系列函式來重置相關統計資訊,比如

  1. pg_stat_reset:Resets all statistics counters for the current database to zero,將全部統計資訊置為零
  2. pg_stat_reset_single_table_counters:將某個表或索引的統計資訊置為零
  3. pg_stat_reset_shared:pg_stat_wal、pg_stat_bgwriter、pg_stat_archiver等統計資訊置為零

那麼清零有什麼後果呢?前面也提到了,autovacuum launcher 程式輪詢所有資料庫,並根據計數以及設定的閾值判斷是否需要對錶進行 vacuum/analyze,因此,重置之後可能會引發表膨脹/凍結等問題。

當然並不是說該函式一無是處,典型場景是調整了某些引數,想對比調整前後的狀態,根據資料庫的這些指標變化趨勢進行對比,比如調整之後死鎖的數量、資料庫的active_time、緩衝區命中率等等,就可以考慮使用 pg_stat_reset 重置,還有個典型例子就是 pg_stat_statements_reset(),定時清空,分析潛在的高危查詢。

小結

因此,讓我們更加嚴謹地回答這位群友的問題:主備除了 pg_stat_all_tables 之外都要自己獨立的"統計資訊",因此主從切換之後,這些計數都是重新計算累積的,為了更好分析潛在的問題,可以按需重置,但是要注意可能的危害。

另外今天晚上看了一下 17 的進度,暫時沒有惹眼特性,indexes_total還算吸引我。

備庫是否有自己的統計資訊?(續)



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027826/viewspace-2996700/,如需轉載,請註明出處,否則將追究法律責任。

相關文章