對innodb 統計信息的控制能夠經過以下幾個經常使用的variables 來實現mysql
一、innodb_stats_persistent:sql
這個參數控制着innodb的統計信息是否持久化到磁盤,先說明一下持久化到磁盤是什麼意思;一般來講統計信息只保存在內存中,也就是說若是mysql服務一重啓那麼以前數據庫
全部的統計信息都沒有了,這個狀況下mysql就要從新收集&計算了;若是統計信息持久化到磁盤了,那麼就能夠直接從磁盤中讀取;異步
爲了真正的能夠達到紅統計信息持久化到磁盤光是innodb_stats_persistent=on是作不到的;innodb_stats_persistent=on 只是說明了打開了mysql把表的統計post
信息持久化到磁盤的能力,可是這個能力用不用不是由表本身說了算;在create table 語句中指定STATS_PERSISTENT=1這個時候表就支持持久化工能了。性能
create table t(x int,y int) STATS_PERSISTENT=1;
二、由1中的描述可知 innodb的表能夠分紅兩大類、一類是支持持久化的表,一類是不支持持久化的表;它們各自的統計信息的收集方式又能夠經過不一樣的變量來控制學習
三、innodb_stats_persistent_sample_pages 持久化統計信息的採樣頁測試
四、innodb_stats_transient_sample_pages 非持久化統計信息的採樣頁優化
五、innodb_stats_auto_recalc 變動超過10%的時候要不要自動收集統計信息spa
六、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統計信息
持久化存儲->
對於InnoDB存儲引發來講,統計信息分別存儲在mysql庫的下面兩張表中:
innodb_table_stats存儲表維度的統計信息,innodb_index_stats存儲索引維度的統計信息。在持久化存儲的狀況下,當設置爲自動更新統計信息的時候且表中有超過10%的數據被更新的時候會執行統計信息的從新計算,並且從新統計不是當即執行的,而是等了一段時間,這個值在MySQL中被定義爲MIN_RECAL_INTERVAL=10(秒)。
易失性存儲->
當innodb_stats_persistent=OFF的時候,MySQL統計信息存儲在內存以後,很顯然當重啓數據庫的時候,這些信息會丟失。
在易失性存儲的狀況下,統計信息從新計算的時機和持久化存儲方式是不一樣的,咱們來看看哪些條件會觸發該狀況下統計信息的從新計算:
瞭解在什麼方式下統計信息會被從新計算對於數據庫的使用優化是有幫助的,好比咱們能夠破壞一些條件而讓事情向着對咱們有力的一面發展。
統計內容:
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優化器的決策?咱們是否能夠經過統計信息來估算表中數據所佔用的存儲空間?……等等。