[轉帖]國產數據庫中統計信息自動更新機制

https://blog.csdn.net/solihawk/article/details/137064277

數據庫中統計信息描述的數據庫中表和索引的大小數以及數據分佈狀況,統計信息的準確性對優化器選擇執行計劃時具有重要的參考意義。本文簡要整理了下傳統數據庫和國產數據庫中統計信息的自動更新機制,以加深瞭解。


1、數據庫統計信息介紹

優化器是數據庫中的重要模塊,其作用是按照一定的判斷原則爲SQL語句找到在當前情形下的最高效執行路徑。優化器的策略主要有基於成本的優化(CBO)和基於規則的優化(RBO):

  • CBO根據SQL語句的代價進行最優執行計劃的選擇。它首先生成一組可能被使用的執行計劃,然後估算每個執行計劃的成本,並最終選擇成本最小的執行計劃。CBO依賴於統計信息來評估執行代價。
  • RBO則基於硬編碼在數據庫中的一系列固定規則來決定SQL執行計劃。隨着數據庫性能要求的提高,RBO逐漸向CBO發展,CBO能夠根據數據的實際情況進行動態調整,在大多數情況下比RBO提供更好的性能。

在優化器CBO執行計劃選擇過程中,統計信息非常關鍵。統計信息主要是描述數據庫中表、索引等對象的大小、規模以及數據分佈狀況的一類信息。主要包括以下幾類:

  • 表的統計信息:例如表的行數、塊數、平均每行的大小等。這些信息描述了表的基本特徵和規模。
  • 索引的統計信息:包括索引的leaf blocks數量、索引字段的行數、不同值的大小等。索引的統計信息對於優化查詢性能尤爲重要,因爲它們直接影響索引的訪問方式和效率。
  • 數據分佈信息:如直方圖(histograms)等,可以展示數據的分佈情況,包括數據的最大值、最小值、平均值以及數據的頻率分佈等。這些信息有助於優化器評估查詢條件的選擇性,從而選擇更高效的執行計劃。

CBO優化器會根據這些統計信息來評估不同查詢執行計劃的成本,並選擇成本最低的計劃來執行查詢。統計信息的準確性和實時性對於優化器的決策至關重要。因此,統計信息需要定期收集和維護,或是手動執行或是系統自動更新,以確保數據庫的性能得到優化。本文將重點關注數據庫中統計信息自動更新的策略。

除了優化SQL查詢,通過統計信息還可以瞭解數據庫中的數據分佈情況、數據庫的熱點數據和冷數據。通過這些信息優化數據庫的存儲結構和訪問策略,提高數據的訪問效率

1.1 SQL語句執行流程

以MySQL數據庫爲例,一條SQL具體的執行過程,如下所示:

在這裏插入圖片描述

總的來說分爲6個步驟:請求、緩存、SQL解析、優化SQL查詢、調用引擎執行、返回結果。

  • 連接:客戶端向MySQL服務器發送一條查詢請求,與connectors交互,連接池認證相關處理。請求會暫時存放在連接池(connection pool)中並由處理器(Management Serveices & Utilities)管理。當該請求從等待隊列進入到處理隊列,管理器會將該請求丟給SQL接口(SQL Interface)。
  • 緩存:SQL接口接收到請求後會將請求進行hash處理,並與緩存中的結果進行比對,如果命中緩存,則立刻返回存儲在緩存中的結果,否則進入下一階段
  • 解析:服務器進行SQL解析(詞法語法)、預處理
  • 優化:再由優化器生成對應的執行計劃
  • 執行:MySQL根據執行計劃,調用存儲引擎的API來執行查詢
  • 結果:將結果返回給客戶端,同時緩存查詢結果。

具體可參看“數據庫系列之InnoDB存儲引擎解密”

MySQL數據庫是基於成本的優化,其中優化器使用了非常多的優化策略來生成一個最優的執行計劃:

  1. 在表裏面有多個索引的時候,決定使用哪個索引;
  2. 重新定義表的關聯順序(多張表關聯查詢時,並不一定按照SQL中指定的順序進行,但有一些技巧可以指定關聯順序)
  3. 優化MIN()和MAX()函數(找某列的最小值,如果該列有索引,只需要查找B+Tree索引最左端,反之則可以找到最大值)
  4. 提前終止查詢(比如:使用Limit時,查找到滿足數量的結果集後會立即終止查詢)
  5. 優化排序(在老版本MySQL會使用兩次傳輸排序,即先讀取行指針和需要排序的字段在內存中對其排序,然後再根據排序結果去讀取數據行,而新版本採用的是單次傳輸排序,也就是一次讀取所有的數據行,然後根據給定的列排序。對於I/O密集型應用,效率會高很多)
2、傳統數據庫中統計信息自動更新策略
2.1 MySQL數據庫中統計信息自動更新機制

MySQL數據庫中的統計信息分爲持久化統計信息和非持久化統計信息,通過參數innodb_stats_persistent控制,默認是開啓的。持久化統計信息將某一時刻的統計信息保存在磁盤中,避免每次查詢時重新計算。如果表更新不是很頻繁,或者沒有達到MySQL必須重新計算統計信息的臨界值,可直接從磁盤上獲取。相比較非持久化統計信息,性能開銷更小。

持久化統計信息還有一個參數innodb_stats_auto_recalc控制是否自動重新計算持久化統計信息,默認開啓。統計信息自動更新策略:

當一張表數據變化超過10%後,MySQL會針對這張表統計信息的更新時間戳做一個判斷,檢查最後一次更新的時間是否超過10秒;如果不到10秒,把這張表加到一個統計信息更新隊列中,到時間了再重新計算;如果超過了10秒,直接重新計算,並且更新時間戳。

另外參數innodb_stats_persistent_sample_pages 控制統計信息採樣的頁數,默認是20,頁數越多,統計信息也就越準確,也就有助於查詢優化器選擇最優的查詢計劃。

統計信息更新完成後,會更新表mysql.innodb_table_stats和mysql.innodb_index_stats中的信息,包括表的行數n_rows、主鍵的數據頁個數clustered_index_size、二級索引的數據頁個數sum_of_other_index_sizes、索引採樣頁個數sample_size等重要信息。

mysql> SELECT * FROM mysql.innodb_table_stats WHERE table_name like 't1'\G
*************************** 1. row ***************************
           database_name: test
              table_name: t1
             last_update: 2024-03-23 14:36:34
                  n_rows: 5
    clustered_index_size: 1
sum_of_other_index_sizes: 2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
2.2 PostgreSQL中統計信息自動更新機制

PostgreSQL數據庫中統計信息自動更新主要是通過自動真空清理(autovacuum)和統計信息收集(analyze)來實現。

1)自動真空清理(autovacuum)

PostgreSQL默認啓用了自動真空清理功能(autovacuum參數控制),它會定期掃描表和索引,清理不再需要的行版本(由於MVCC機制產生的),並釋放空間。當表自上一次vacuum後更新記錄數超過閾值後,會觸發autovacuum動作,計算方法如下:

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

其中vacuum base threshold爲autovacuum_vacuum_threshold(默認爲50)、vacuum scale factor 爲autovacuum_vacuum_scale_factor(默認爲10%)、the number of tuples爲pg_class.reltuples。

2)統計信息收集Analyze

當表或者索引的數據變化超過一定的閾值後,PostgreSQL也會自動進行統計信息收集操作。

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

其中analyze base threshold爲autovacuum_analyze_threshold(默認爲50)、analyze scale factor 爲autovacuum_analyze_scale_factor(默認爲10%)、the number of tuples爲pg_class.reltuples。

2.3 Oracle數據庫統計信息自動更新機制

Oracle數據庫中默認開啓統計信息自動收集任務,使用的任務爲gather_stats_prog。gather_stats_prog調用了DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC存儲過程。在Oracle數據庫中通過設置不同的維護窗口形式,設定窗口運行的開始時間、持續時間:

SQL> SELECT a.WINDOW_NAME,a.REPEAT_INTERVAL,a.duration FROM dba_scheduler_windows a WHERE ENABLED = 'TRUE';
WINDOW_NAME         REPEAT_INTERVAL                                          DURATION         
 ------------------  -------------------------------------------------------  -----------------
 MONDAY_WINDOW       freq=daily;byday=MON;byhour=22;byminute=0; bysecond=0    +000 04:00:00
 TUESDAY_WINDOW      freq=daily;byday=TUE;byhour=22;byminute=0; bysecond=0    +000 04:00:00
 WEDNESDAY_WINDOW    freq=daily;byday=WED;byhour=22;byminute=0; bysecond=0    +000 04:00:00
 THURSDAY_WINDOW     freq=daily;byday=THU;byhour=22;byminute=0; bysecond=0    +000 04:00:00
 FRIDAY_WINDOW       freq=daily;byday=FRI;byhour=22;byminute=0; bysecond=0    +000 04:00:00
 SATURDAY_WINDOW     freq=daily;byday=SAT;byhour=6;byminute=0; bysecond=0     +000 20:00:00
 SUNDAY_WINDOW       freq=daily;byday=SUN;byhour=6;byminute=0; bysecond=0     +000 20:00:00
————————————————
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如果參數STATISTICS_LEVEL的值爲TYPICAL(默認)或者ALL,則DBA_TAB_MODIFICATIONS會記錄自上次自動統計信息收集完成之後對目標表的insert、update、delete的操作影響行數,並且還會記錄自從上次自動收集統計信息之後是否發生過truncate。如果DBA_TAB_MODIFICATIONS中記錄的INSERT+UPDATE+DELETE所影響的行記錄之和超過了DBA_TABLES中目標表記錄數的10%,或者是自上次統計信息收集完成之後目標表執行過truncate操作,那麼Oracle會認爲目標表的統計信息已經失效,自動統計信息收集作業就會對目標表重新收集統計信息。

如果想禁用或者開啓統計信息自動收集任務:

#禁用統計信息自動收集
SQL> EXEC dbms_auto_task_admin.disable(client_name=> 'auto optimizer stats collection',operation=> NULL,window_name=> NULL);
#啓用統計信息自動收集
SQL> EXEC dbms_auto_task_admin.enable(client_name=> 'auto optimizer stats collection',operation=> NULL,window_name=> NULL);
#禁用維護窗口中統計信息收集
EXEC dbms_auto_task_admin.disable(client_name=>'auto optimizer stats collection',operation=>NULL,window_name=>'TUESDAY_WINDOW');
#啓用維護窗口中統計信息收集
EXEC dbms_auto_task_admin.enable(client_name=>'auto optimizer stats collection',operation=>NULL,window_name=>'TUESDAY_WINDOW');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
2.4 DB2數據庫統計信息自動更新機制

DB2數據庫中支持統計信息的自動收集,有兩種方式:一是通過配置auto_stmt_stats參數在語句編譯時同步收集統計信息;另一種是RUNSTATS命令後臺執行的時候,配置auto_runstats在後臺自動收集統計信息。默認情況下,這兩個參數都是啓用狀態。相比較異步統計信息收集,實時統計信息更爲及時準確,爲優化器生成最佳的執行計劃以提升查詢性能。

自動收集統計信息某些情況下可能會OLTP聯機類業務的性能會產生影響,在實際使用過程中進行配置將影響降到最低:

  • 使用RUNSTATS命令進行異步的統計信息收集操作
  • 對於每個查詢,同步統計信息收集操作的時間限制爲5秒。如果同步收集操作超出時間限制,那麼將提交異步收集請求。
  • 實時同步的統計信息存儲在高速緩存中,避免更新系統目錄中涉及的內存使用情況和可能的鎖定爭用。後續SQL編譯請求可以使用統計信息高速緩存中的統計信息。
  • 對於每個表,只能執行一個同步統計信息收集操作。

另外,在開啓統計信息自動收集需開啓參數配置AUTO_MAINT和AUTO_TBL_MAINT,AUTO_MAINT用於指定自動維護任務的配置文件,AUTO_TBL_MAINT用於指定自動維護任務是否包括表級別的統計信息收集。

    Automatic maintenance                      (AUTO_MAINT) = ON
      Automatic database backup               (AUTO_DB_BACKUP) = OFF
      Automatic table maintenance             (AUTO_TBL_MAINT) = ON
          Automatic runstats                   (AUTO_RUNSTATS) = ON
             Real-time statistics            (AUTO_STMT_STATS) = ON
                Statistical views              (AUTO_STATS_VIEWS) = OFF
                 Automatic sampling               (AUTO_SAMPLING) = OFF
                Automatic column group statistics (AUTO_CG_STATS) = OFF
          Automatic reorganization              (AUTO_REORG) = OFF
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
3、國產數據庫中統計信息更新策略
3.1 TiDB數據庫

TiDB數據庫中使用變量tidb_analyze_version 控制統計信息的收集,在 v5.3.0 及之後的版本中,該變量的默認值爲 2。Version 2的統計信息避免了Version 1中因爲哈希衝突導致的在較大的數據量中可能產生的較大誤差,並保持了大多數場景中的估算精度。

在這裏插入圖片描述

TiDB中除了ANALYZE Table手動收集統計信息外,也支持自動更新。如果表發生增刪改時,TiDB會自動更新表的總行數以及修改的行數,統計信息更新的週期爲20*stats-lease。stats-lease默認配置爲3s,如果將其指定爲0,那麼統計信息將不會自動更新。

另外如果表中修改的行數與總行數的比值大於tidb_auto_analyze_ratio(默認值爲0.5),並且當前時間在tidb_auto_analyze_start_time和tidb_auto_analyze_end_time之間時,TiDB會在後臺執行ANALYZE TABLE tbl語句自動更新這個表的統計信息。

在這裏插入圖片描述

爲了避免小表因爲少量數據修改而頻繁觸發自動更新,當表的行數小於1000時,TiDB不會觸發對此表的自動更新。同時通過參數tidb_enable_auto_analyze也可以關閉統計信息自動更新機制,以避免自動更新統計信息消耗過多資源,影響在線業務。

3.2 OceanBase數據庫

在OceanBase數據庫優化器中,統計信息以普通數據的形式存儲在內部表中,並且會在本地維護統計信息的緩存,以提高優化器對統計信息的訪問速度。統計信息包含表統計信息(Table Level Statistics)和列統計信息(Column Level Statistics)兩種類型。

OceanBase數據庫中支持手動收集統計信息和自動收集統計信息,同時支持對應的視圖查詢收集的統計信息,包括Oracle模式和MySQL模式。其中OceanBase統計信息自動收集類似Oracle的任務窗口形式,基於DBMS_SCHEDULER系統包實現的MAINTENANCE WINDOW來實現每日的自動統計信息收集,如下所示:

在這裏插入圖片描述

自動統計信息收集任務的開啓關閉也是通過設置MAINTENANCE WINDOW的屬性:

DBMS_SCHEDULER.DISABLE($window_name);
DBMS_SCHEDULER.ENABLE($window_name);
  • 1
  • 2

OceanBase數據庫中表的統計信息過期判斷標準爲:如果當前表增量的DML次數(上一次收集統計信息時DML次數到本次收集統計信息期間發生的增/刪/改總次數)超過設置的閾值時就會過期。閾值的默認值是10%,閾值可以通過peres調整設置。具體的更新策略如下:

  • 系統表和非分區用戶表的自動收集策略:
    • 如果表沒有GLOBAL級別的統計信息,自動收集統計信息。
    • 如果表有GLOBAL級別的統計信息,但是統計信息已經過期,則自動收集統計信息。
    • 否則,OceanBase數據庫優化器不會自動收集統計信息。
  • OceanBase數據庫分區用戶表的自動收集策略:
    • 如果表沒有任何統計信息,自動收集所有的統計信息。
    • 如果表有分區級別的統計信息,但是沒有GLOBAL級別統計信息,則採用增量的方式自動收集統計信息。
    • 如果表有GLOBAL級別統計信息,但是已經過期,則自動收集所有的統計信息。
    • 如果表有GLOBAL級別統計信息,但是沒有全部過期,只是部分分區的統計信息過期,則自動收集統計信息過期的分區統計信息,同時採用增量的方式推導GLOBAL級別統計信息。
3.3 OpenGauss數據庫

OpenGauss數據庫類似PostgreSQL數據庫的做法,通過AutoVacuum機制來實現統計信息的自動更新。AutoVacuum後臺有常駐線程AVClauncher,這個線程會定期喚起AVCWorker線程來執行實際的vacuum與analyze任務。一旦識別出過時數據,AutoVacuum會執行VACUUM操作,將過時數據行標記爲可重用的空間,並更新表的統計信息,以確保查詢優化器能夠做出正確的執行計劃。

當autovacuum設置爲on時,系統會定時啓動autovacuum線程(自動清理線程)自動執行VACUUM和ANALYZE命令,回收被標識爲刪除狀態的記錄空間,並更新表的統計數據。

  • 對於空表而言,當表中插入數據的行數大於50時,會觸發表自動進行ANALYZE。
  • 對於表中已有數據的情況,閾值設定爲
autovacuum_analyze_threshold+ autovacuum_analyze_scale_factor*reltuples
  • 1

其中autovacuum_analyze_threshold表示當表上被刪除、插入或更新的記錄數超過設定的閾值時纔會對這個表執行ANALYZE操作,默認值爲50;autovacuum_analyze_scale_factor表示觸發一個ANALYZE時增加到autovacuum_analyze_threshold的表大小的縮放係數,默認值爲10%;reltuples是表的總行數。

同時,autovacuum生效還依賴於下面幾個GUC參數:

  • track_counts參數需要設置爲on,表示開啓收集收據庫統計數據功能。
  • autovacuum_max_workers參數需要大於0,該參數表示能同時運行的自動清理線程的最大數量。
  • autovacuum_mode參需要配置允許進行analyze。

另外autoanalyze設置了超時時間,在對某張表做autoanalyze時,如果該表的analyze時長超過了autoanalyze_timeout,則自動取消該表此次analyze。

3.4 達夢數據庫

在達夢數據庫中統計信息包括表的行數、塊數、平均每行的大小、索引的高度、葉子節點數以及索引字段的行數等描述數據庫中表和索引的大小數以及數據分佈狀況等的一類信息。DM數據庫中統計信息收集是通過DBMS_STATS包實現的,支持手動收集和自動收集,其自動收集統計信息配置如下:

--打開表數據量監控開關,參數值爲 1 時監控所有表,2 時僅監控配置表
SP_SET_PARA_VALUE(1,'AUTO_STAT_OBJ',2);

--設置 SYSDBA.T 表數據變化率超過 15% 時觸發自動更新統計信息
DBMS_STATS.SET_TABLE_PREFS('SYSDBA','T','STALE_PERCENT',15);

--配置自動收集統計信息觸發時機
SP_CREATE_AUTO_STAT_TRIGGER(1, 1, 1, 1,'14:36', '2020/3/31',60,1);

/*
函數各參數介紹
SP_CREATE_AUTO_STAT_TRIGGER(
TYPE INT, --間隔類型,默認爲天
FREQ_INTERVAL INT, --間隔頻率,默認 1
FREQ_SUB_INTERVAL INT, --間隔頻率,與 FREQ_INTERVAL 配合使用
FREQ_MINUTE_INTERVAL INT, --間隔分鐘,默認爲 1440
STARTTIME VARCHAR(128), --開始時間,默認爲 22:00
DURING_START_DATE VARCHAR(128), --重複執行的起始時間,默認 1900/1/1
MAX_RUN_DURATION INT, --允許的最長執行時間(秒),默認不限制
ENABLE INT --0 關閉,1 啓用 --默認爲 1
);
*/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
4、各類數據庫統計信息自動收集策略對比

上文對比了幾種傳統數據庫和國產數據庫中統計信息自動收集的策略,像Oracle和DB2數據庫中統計信息的收集對性能和交易可能有潛在的風險,實際生產環境中默認是不開啓的。像MySQL系列的數據庫(TDSQL for MySQL、GoldenDB等),默認開啓統計信息自動收集。在實際運行過程中,如果由於統計信息沒更新導致應用出現慢SQL執行計劃變化,建議手動觸發統計信息的及時更新。

在這裏插入圖片描述


參考資料:

  1. https://dev.mysql.com/doc/refman/8.3/en/innodb-performance-optimizer-statistics.html
  2. https://www.postgresql.org/docs/15/runtime-config-autovacuum.html
  3. https://blog.csdn.net/weixin_30895723/article/details/106537408
  4. https://www.ibm.com/docs/zh/db2/11.5?topic=statistics-automatic-collection
  5. https://docs.pingcap.com/zh/tidb/stable/statistics
  6. https://docs-opengauss.osinfra.cn/zh/docs/5.0.0/docs/DatabaseReference
  7. https://eco.dameng.com/document/dm/zh-cn/pm/query-optimization
文章知識點與官方知識檔案匹配,可進一步學習相關知識
雲原生入門技能樹首頁概覽18418 人正在系統學習中
牧羊人的方向
微信公衆號
分享數據庫、分佈式和容器相關技術
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章