1. 程式人生 > >MySQL innodb統計信息

MySQL innodb統計信息

行數據 gin 客戶端 inno pos 存儲方式 pda 統計數據 interval

對innodb 統計信息的控制可以通過如下幾個常用的variables 來實現

1、innodb_stats_persistent:

  這個參數控制著innodb的統計信息是否持久化到磁盤,先說明一下持久化到磁盤是什麽意思;通常來說統計信息只保存在內存中,也就是說如果mysql服務一重啟那麽之前

  所有的統計信息都沒有了,這個情況下mysql就要重新收集&計算了;如果統計信息持久化到磁盤了,那麽就可以直接從磁盤中讀取;

  為了真正的可以達到紅統計信息持久化到磁盤光是innodb_stats_persistent=on是做不到的;innodb_stats_persistent=on 只是說明了打開了mysql把表的統計

  信息持久化到磁盤的能力,但是這個能力用不用不是由表自己說了算;在create table 語句中指定STATS_PERSISTENT=1這個時候表就支持持久化工能了。

  create table t(x int,y int) STATS_PERSISTENT=1;

2、由1中的描述可知 innodb的表可以分成兩大類、一類是支持持久化的表,一類是不支持持久化的表;它們各自的統計信息的收集方式又可以通過不同的變量來控制

3、innodb_stats_persistent_sample_pages 持久化統計信息的采樣頁

4、innodb_stats_transient_sample_pages 非持久化統計信息的采樣頁

5、innodb_stats_auto_recalc 變更超過10%的時候要不要自動收集統計信息

6、innodb_stats_on_metadata 執行show table status | information_schema.tables 時是否自動收集統計信息

7. 我們將一條查詢SQL提交給MySQL之後,MySQL在進行真正的查詢操作之前通常會經歷兩個階段:SQL解析和查詢優化。在SQL解析過程中,MySQL會將SQL解析為一個樹狀結構,而在查詢優化階段,MySQL會決定以什麽方式進行查詢,那麽MySQL以什麽方式進行查詢的抉擇依據是什麽呢?答案就是這篇文章要介紹的MySQL統計信息,因為我廠的MySQL實際使用的是Percona分支,因此本文相關的實驗知識是基於Percona分支的。

帶著問題

  • MySQL統計的信息包括什麽內容?是用來做什麽的?
  • MySQL統計信息基於表和索引,表和索引是要變化的,那麽MySQL是如何保證數據的時效性的?
  • MySQL的統計機制有什麽問題?統計策略如何選擇?


MySQL統計信息

持久化存儲->
對於InnoDB存儲引起來說,統計信息分別存儲在mysql庫的下面兩張表中:

  • innodb_table_stats
  • innodb_index_stats

innodb_table_stats存儲表維度的統計信息,innodb_index_stats存儲索引維度的統計信息。在持久化存儲的情況下,當設置為自動更新統計信息的時候且表中有超過10%的數據被更新的時候會執行統計信息的重新計算,而且重新統計不是立即執行的,而是等了一段時間,這個值在MySQL中被定義為MIN_RECAL_INTERVAL=10(秒)。

易失性存儲->

當innodb_stats_persistent=OFF的時候,MySQL統計信息存儲在內存之後,很顯然當重啟數據庫的時候,這些信息會丟失。

在易失性存儲的情況下,統計信息重新計算的時機和持久化存儲方式是不同的,我們來看看哪些條件會觸發該情況下統計信息的重新計算:

  • 執行ANALYZE TABLE命令
  • 執行如下命令:SHOW TABLE STATUS, SHOW INDEX。
  • 在innodb_stats_on_metadata選項開啟的情況下查詢INFORMATION_SCHEMA.TABLES表或INFORMATION_SCHEMA.STATISTICS表
  • 通過--auto-rehash參數開啟客戶端連接,--auto-rehash參數導致InnoDB表被打開,InnoDB表被打開導致統計信息被重新計算
  • 表被第一次打開
  • 距離上次統計之後,表的1/16的數據被更新


了解在什麽方式下統計信息會被重新計算對於數據庫的使用優化是有幫助的,比如我們可以破壞一些條件而讓事情向著對我們有力的一面發展。

統計內容:
MySQL統計信息包括哪些內容呢?MySQL分別從表維度和索引維度構建統計信息。

表統計信息:
innodb_table_stats表存儲的是表維度的統計信息,innodb_table_stats表有6個字段,他們的各字段相關定義以及含義如下表所示:

字段名 字段類型 字段含義
database_name verchar(64) 統計信息所屬表的數據庫名
table_name verchar(64) 統計信息所屬的表名
last_update timestamp 統計信息最後一次更新的時間
n_rows bigint(20) unsigned 表所包含的行數
clustered_index_size bigint(20) unsigned 聚集索引的頁的數量
sum_of_other_index_size bigint(20) unsigned 其他索引所占的頁的數量


我找了一張我們現存的表測試一下:

如上圖所示,CL_CommunityNavStatInfo表當前的記錄數為5281。

上面我們看到表中實際有5281行數據,但是統計出來的是5228行數據,這是因為什麽呢?這個問題留在精度問題部分進行討論。

索引統計信息
innidb_index_stats表存儲的是索引維度的統計信息,innodb_index_stats表有8個字段,他們的各字段相關定義以及含義如下表所示:

字段名  字段類型  字段含義
database_name varchar(64) 統計信息所屬表的數據庫名
table_name varchar(64) 統計信息所屬表名
index_name varchar(64) 統計信息所屬索引名
last_update timestamp 統計信息更新的時間
stat_name varchar(64) 統計信息名稱
stat_value bigint(20) unsigned 統計值
sample_size bigint(20) unsigned 采樣大小
stat_description varchar(64) 統計描述信息

我們依然使用上面測試用到的CL_CommunityNavStatInfo表進行測試,先看看CL_CommunityNavStatInfo表的索引定義:


CL_CommunityNavStatInfo表建立了三個索引,我們通過innodb_index_stats表來看看這三個索引的統計信息:


上圖為表CL_CommunityNavStatInfo所有索引的統計信息,比如最後一行,size代表主鍵聚集所以所占頁數大小為161,葉子節點所占空大小為128頁,id的區分度為5228,這個數字其實也是統計的表的行數,sample_size為20表示采樣頁數。

精度問題
采樣大小

上面提到了sample_size這個數字,其實MySQL的統計數據是基於采樣數據估算的,而采樣的大小是用戶可控的,默認值為20,我們可以通過修改采樣大小來控制統計信息的精確性,同時這也會影響性能。比如我們用下面命令將采樣大小調整為200:

SET global innodb_stats_persistent_sample_pages=200;
200是我們隨表挑的一個大於所有數據頁數的數字,這樣保證統計信息基於全量數據統計,通過ANALYZE TABLE CL_CommunityNavStatInfo;命令重新統計之後,再來看看統計信息:



是不是無比的準確?再繼續看看索引的統計信息:


現在的統計信息已經是基於全量的數據統計了,雖然數據準確了,但是我們同時也損失了一部分的性能。

統計時機

定時輪訓

統計時機關心的是什麽時候進行統計信息的更新。innodb_stats_auto_recalc參數用於控制是否讓MySQL自行在需要的時候更新統計信息,當它的值為ON的時候,統計信息的重新計算是異步的,MySQL有一個線程專門用來做這個事情,這個線程每隔10秒鐘回去看看要不要進行統計,否則我們需要使用ANALYZE TABLE命令來保證統計信息的時效性。那麽我們是選擇將統計信息的更新權利完全霸占還是將其授權給MySQL讓它自行更新呢?這個問題留給讀者思考。

總結

本文分別從MySQL統計信息的存儲、內容、精度和統計時機方面對MySQL統計信息進行了一定的學習,了解了MySQL統計信息的相關知識,我認為我們至少可以解決一些實際問題了。比如:

我們當前應用的數據源MySQL關於統計方面的配置有沒有問題?
我們是否可以試著通過調整采樣大小來控制統計信息的精確度?從而影響SQL優化器的決策?
我們是否可以通過統計信息來估算表中數據所占用的存儲空間?
……
等等。

MySQL innodb統計信息