MySQL 表如何計算統計信息-愛可生

2021-01-07 騰訊網

本篇介紹 MySQL 表如何計算統計信息。表統計信息是資料庫基於成本的優化器最重要的參考信息;統計信息不準確,優化器可能給出不夠優化的執行計劃或者是錯誤的執行計劃。

對統計信息的計算分為非持久化統計信息(實時計算)與持久化統計信息

非持久化統計信息

統計信息沒有保存在磁碟上,而是頻繁的實時計算統計信息;

每次對表的訪問都會重新計算其統計信息;

假設針對一張大表的頻繁查詢,那麼每次都要重新計算統計信息,很耗費資源。

持久化統計信息

把一張表在某一時刻的統計信息值保存在磁碟上;

避免每次查詢時重新計算;

如果表更新不是很頻繁,或者沒有達到 MySQL 必須重新計算統計信息的臨界值,可直接從磁碟上獲取;

即使 MySQL 服務重啟,也可以快速的獲取統計信息值;

統計信息的持久化可以針對全局設置也可以針對單表設置。

接下來,詳細說 MySQL 統計信息如何計算,何時計算,效果評估等問題。

在 MySQL Server 層來控制是否自動計算統計信息的分布,並且來決策是持久化還是非持久化。

一、持久化統計相關參數:

innodb_stats_persistent :是否開啟統計信息持久化,默認開啟。

innodb_stats_auto_recalc :是否自動重新計算持久化統計信息,默認開啟。

二、具體的更新策略為:

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

目前這個超時時間寫死在 MySQL 代碼裡,暫時不能更改。不過在某些 MySQL 分支版還可以控制這個時間,比如 Percona。

innodb_stats_include_delete_marked :更新持久化統計信息時,是否會計算已經標記為刪除的行。默認是關閉的,會獲取未提交的髒數據。開啟這個選項,MySQL 計算統計信息時只會考慮已經提交的數據。

innodb_stats_persistent_sample_pages :用於更新持久化索引分布或者其他統計信息的隨機基數頁,默認 20 個。頁數越多,統計信息也就越準確,也就有助於查詢優化器選擇最優的查詢計劃。

什麼時候考慮更改這個值呢?

當查詢計劃不是很準確時。比如對比指定表在系統表 mysql.innodb_index_stats 的數據跟 distinct 查詢的結果,如果相差太大,可以考慮增加這個值。

當 analyze table 變的非常慢時,可能是這個值設置的太大了,此時要考慮減小這個值。

三、非持久化統計信息參數

innodb_stats_transient_sample_pages:設置非持久化統計信息的採樣頁數目,默認 8 個。

innodb_stats_on_metadata:當統計信息配置為非持久化時生效,默認關閉。參數 innodb_stats_persistent 為 0 或者建表時屬性 STATS_PERSISTENT=0 才起作用。

當開啟後,對以下元數據的訪問會自動更新統計信息:

show table status

show index

information_schema.tables

information_schema.statistics

所以開啟這個選項會額外增加訪問表的開銷,特別是大表。

還有一些其他的場景會自動更新非持久化統計信息,比如:

表第一次被訪問;

InnoDB 檢測到有十六分之一的表自從上次統計信息計算後被更新了,這時觸發自動更新;

MySQL 客戶端默認選項 --auto-rehash 打開所有 InnoDB 表,導致所有 InnoDB 表被自動更新統計信息;

四、表屬性控制

STATS_AUTO_RECALC

用來指定是否要自動計算指定 InnoDB 表的統計信息。

三個值:default, 0, 1

default:也就是默認值,依賴 server 端參數 innodb_stats_auto_recalc 的設置效果

0:表示禁用統計信息的自動重新計算,也就是永遠不重新計算,需要手動執行 analyze table

1:表示當表數據有 10% 的數據變化後,則重新計算持久化統計信息。

STATS_PERSISTENT

用來指定是否要開啟指定 InnoDB 表的統計信息持久化。

三個值:default, 0, 1

default:依賴 server 端參數 innodb_stats_persistent 的設置

0:表示不需要持久化統計信息

1:表示開啟持久化統計信息

STATS_SAMPLE_PAGES

用來指定計算統計信息時的採樣頁數量。

五、手動更新統計信息

analyze table 用來手動更新表統計信息。建議在業務低峰時執行。

六、持久化表統計元數據信息

優化器通過兩張元數據表裡的數據來決定查詢最優執行計劃。

表統計信息保存在表 mysql.innodb_table_stats 裡

比如表 ytt_sample_persist 的統計信息

重要列說明:

n_rows:表的行數

clustered_index_size:主鍵的數據頁個數

sum_of_other_index_sizes:二級索引的數據頁個數

以下例子可以看到表 ytt_sample_persist 表行數大概為 36W 行,聚簇索引頁數為 15162,二級索引頁數為 4113。

這些值都是基於採樣頁來計算的,所以是一個預估值。

mysql> select n_rows,clustered_index_size,sum_of_other_index_sizes from innodb_table_stats where database_name ='ytt' and table_name = 'ytt_sample_persist';

+---+--+-+

| n_rows | clustered_index_size | sum_of_other_index_sizes |

+---+--+-+

| 356960 | 15162 | 4113 |

+---+--+-+

1 row in set (0.00 sec)

其實表 ytt_sample_persist 真實數據為 40W 行。

mysql> select count(*) from ytt_sample_persist;++| count(*) |++| 406644 |++1 row in set (0.90 sec)

強制更新統計信息,

mysql> analyze table ytt_sample_persist;+----+----+++| Table | Op | Msg_type | Msg_text |+----+----+++|+----+----+++1 row in set (0.28 sec)

統計信息已經更新為最新,數據又離真實數據接近一點。

mysql> select n_rows,clustered_index_size,sum_of_other_index_sizes from innodb_table_stats where database_name ='ytt' and table_name ='ytt_sample_persist';

+---+--+-+

| n_rows | clustered_index_size | sum_of_other_index_sizes |

+---+--+-+

| 387202 | 16380 | 4562 |

+---+--+-+

1 row in set (0.01 sec)

索引統計信息保存在表 mysql.innodb_index_stats 裡

比如表 ytt_sample_persist 索引統計信息

Index_name:索引名字

stat_name / stat_value:統計名字和對應的值

sample_size:採樣頁個數

stat_description:統計名字詳細信息描述

比如表 ytt_sample_persist 的聯合主鍵統計信息如下:

stat_name 顯示的值 n_diff_pfx01 代表聯合主鍵中第一個列狀態名字,對應的 stat_value 為第一個列的唯一值個數;n_diff_pfx02 代表第二列狀態名字,對應的 stat_value 為前兩列的唯一值個數,以此類推。

n_leaf_pages /stat_value 代表葉子節點的頁數目;size 代表索引的總頁數。

mysql> select index_name,stat_name,stat_value,sample_size,stat_description from innodb_index_stats where database_name ='ytt' and table_name ='ytt_sample_persist' and index_name = 'PRIMARY';

+--+----+--+---++

| index_name | stat_name | stat_value | sample_size | stat_description |

+--+----+--+---++

| PRIMARY | n_diff_pfx01 | 14137 | 20 | i1 |

| PRIMARY | n_diff_pfx02 | 75398 | 20 | i1,i2 |

| PRIMARY | n_diff_pfx03 | 387202 | 20 | i1,i2,i3 |

| PRIMARY | n_leaf_pages | 15708 | NULL | Number of leaf pages in the index |

| PRIMARY | size | 16380 | NULL | Number of pages in the index |

+--+----+--+---++

5 rows in set (0.00 sec)

那關於表的統計信息相關知識點就介紹到此,了解這塊對我們優化 SQL 來說,會更加得心應手。

總結

簡單總結下,本篇主要介紹了 MySQL表和索引的統計信息計算,包括持久化統計信息與非持久化統計信息。如果後期有 SQL 走的執行計劃不對,或者不是最優的,那就可以斷定相關統計信息太舊了,需要及時更新。比如有時候多表 JOIN 的順序不對,導致查詢效率變差,需要人工介入等等。

相關焦點

  • MySQL 優化案例 - select count-愛可生
    二、原 SQL 分析Server version: 5.7.24-log MySQL Community Server (GPL)SQL 如下,僅僅就是統計 api_runtime_log這張表的行數,一條簡單的不能再簡單的 SQL:select count(*) from api_runtime_log;我們先去運行一下這條 SQL
  • MySQL如何計算統計redo log大小
    在MySQL中如何計算、統計重做日誌(redo log)的生成情況呢? 例如10分鐘內,生成了多少M的redo log呢?30分鐘內又生成了多少M的redo log.....。MySQL沒有像Oracle中那樣的系統視圖統計這些數據,但是我們可以通過一些方法曲線的統計二進位日誌的生成量。
  • MySQL中InnoDB-Cluster 日常運維掃盲-愛可生
    目前任職於愛可生,為各大運營商及銀行金融企業提供 MySQL 相關技術支持、MySQL 相關課程培訓等工作。 本文來源:原創投稿 *愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 本篇是《innodb-cluster 掃盲-安裝篇》的續篇。
  • MySQL 數據校驗工具-愛可生
    其原理是在主庫執行基於 statement 的 SQL 語句來生成主庫數據塊的checksum,把相同的 SQL 語句傳遞到從庫執行,並在從庫上計算相同數據塊的 checksum,最後,比較主從庫上相同數據塊的 checksum 值,由此判斷主從數據是否一致。它能在非常大的表上工作的一個原因是,它把每個表分成行塊,並檢查每個塊與單個替換。選擇查詢。它改變塊的大小,使校驗和查詢在所需的時間內運行。
  • MySQL裡快速找到 binlog 中是否有大事務-愛可生
    我們就過濾這一段信息, 然後我們將其中的位置信息過濾出來, 本期沒有關於 MySQL 太多的知識點,只是活用 Linux 的命令,可以簡單高效獲取 binlog 的信息。
  • 如何寫一個自己的 bcc 工具觀測 MySQL-愛可生
    作者:鄧歡  愛可生 DMP 團隊開發成員,主要負責 DMP 相關開發。  本文來源:原創投稿  *愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。  社區之前有一篇文章《如何使用 bcc 工具觀測 MySQL 延遲》,介紹了 bcc 是什麼以及如何用 bcc 項目提供的工具觀測 MySQL。
  • MySQL 資料庫表上做查詢慢的原因-愛可生
    但使用 exists 子句進行子查詢的代價,顯然不可能為 0,MySQL 對這個代價的計算可能有誤。我們得來看看 MySQL 是如何計算這個代價的:執行 exists 子查詢的代價 = 執行一次子查詢的代價 * 子查詢需要執行的次數顯然這個子查詢不可能只需要執行 0 次這裡需要做一個額外的思考:在這個場景下,子查詢需要執行的次數,與父查詢的行數相同
  • MySQL 大量 Opening tables 案例分析-愛可生
    之前遇到過類似的問題現象,是由於 MySQL 開啟了AHI(自適應哈希索引)後如果DROP或TRUNCATE一張大表,  3. dict_stats_thread:統計信息更新線程,最後處於buf_flush_wait_flushed。
  • 詳解MySQL|MySQL中間件DBLE-第五章 後端資料庫相關特性-愛可生
    第二章 DBLE的高級特性2.2 後端資料庫的相關特性DBLE系列公開課簡介課程目錄適用人群正在使用DBLE或MyCat的用戶當前中間件無法滿足業務需求的用戶運維大體量資料庫,需要考慮分庫分表的DBA為資料庫架構選型發愁的研發人員講師介紹如何獲取課程DBLE系列公開課發布在「愛可生開源社區官網
  • MySQL性能調優之對系統最大打開文件數限制調整-愛可生
    系統參數與文件描述符的關係- max_connection & fd : 每一個MySQL connection 都需要一個文件描述符;- table_open_cache & fd 打開一張表至少需要一個 文件描述符,如打開MyISAM需要兩個fd ; - 系統最大打開文件數可以通過 ulimit -n查看。
  • [MySQL FAQ]系列 — 怎麼計算打開文件數
    有時候,我們會遇到類似下面的報錯信息:[ERROR] /usr/local/mysql/bin/mysqld: Can't open file: './yejr/access.frm' (errno: 24)[ERROR] /usr/local/mysql/bin/mysqld: Can't open file: '.
  • 為什麼這次 MySQL 崩潰恢復要這麼久-愛可生
    作者:xuty本文來源:原創投稿 *愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。,fil_ibd_open(fil0fil.cc:3969),dict_check_sys_tables(dict0load.cc:1465),dict_check_tablespaces_and_store_max_id(dict0load.cc:1525),innobase_start_or_create_for_mysql
  • MySQL 變量及性能狀態查看知識技巧
    如何查看查看MySQL性能?  方法一的使用:  查看MySQL伺服器配置信息 :mysql> show variables;  查看MySQL伺服器運行的各種狀態值 :mysql> show global status;  慢查詢:mysql> show variables like '%s%';  mysql
  • [精選] MySQL分庫分表後用PHP如何來完美操作
    用戶類庫、商品類庫、訂單類庫、日誌類、統計類庫...2)按日期分表一些日誌、統計類的可以按年、月、日、周分表如:點擊量統計click_201901、click_2019023)使用mysql的merge先把分表創建好,然後創建總表指定engine= MERGE UNION=(table1,table2) INSERT_METHOD = LAST;
  • MySQL 表上做查詢慢出現狀況-愛可生
    現在用一下 DBA 三板斧,看看執行計劃:感覺有點慘,由於 information_schema.columns 是元數據表,沒有必要的統計信息。掃描 B 表中的所有記錄,找到滿足條件的記錄,存放在臨時表 C 中,建好索引2.
  • 生產MySQL資料庫執行一次analyze採集信息,應用炸了
    故障簡介     之前,有開發找到我,說應用的某個功能查詢比以前慢了很多,讓開發提供了慢的SQL語句,去對應的MySQL資料庫看了一下執行計劃,發現執行計劃不正確,第一反應就是其中的一個表的統計信息不準確
  • MySQL最常用分組聚合函數
    )求累加和  ①每個組函數接收一個參數  ②默認情況下,組函數忽略列值為null的行,不參與計算  ③有時,會使用關鍵字distinct剔除欄位值重複的條數注意:  1)當使用組函數的select語句中沒有group by子句時,中間結果集中的所有行自動形成一組,然後計算組函數;  2)組函數不允許嵌套
  • PHP+MySQL實現對一段時間內每天數據統計優化操作實例
    (商務合作聯繫QQ號:2230304070)http://www.jb51.net/article/136685.htm這篇文章主要介紹了PHP+MySQL實現對一段時間內每天數據統計優化操作,結合具體實例形式分析了php針對mysql查詢統計相關優化操作技巧
  • 深入理解MySQL8.0直方圖
    mysql>SHOW INDEX FROM table_name執行計劃裡出現的Cardinality(基數)欄位,是非常重要的:基數計算是採樣統計,如果把整張表取出來一行行統計,雖然可以得到精確的結果,但是代價太高。
  • mysql大表中count()的用法以及mysql中count()的優化
    本篇文章給大家帶來的內容是關於mysql大表中count()的用法以及mysql中count()的優化,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。一個單表中包含有6000w+的數據,然而你又不能拆分.需要分別統計表中有多少數據,A產品有多少,B產品有多少這幾個數據.