“談談MySQL的基數統計”

賜我白日夢發表於2020-11-10

**

Hi,大家好!我是白日夢。

今天我要跟你分享的話題是:“大家常說的基數是什麼?”

推薦閱讀原文連結

https://mp.weixin.qq.com/s/FgxwAFQbEjv5i-TxjvLK6Q

這是白日夢的《為研發同學定製的MySQL面試指南》系列文章的第1篇文章,全書110篇文章,連載中!

全文110篇!以問答的方式,由淺入深的幫你應對各類MySQL面試題的狂轟濫炸!

當然也不乏會分享一些高階讀寫分離資料庫中介軟體原理及落地的技術實現,為你揭開資料庫中介軟體神祕的面紗!

面試官都關注了!你還在猶豫什麼呢?

碼字不易,感謝閱讀,感謝關注,感謝在看,感謝轉發,保護!

可加我微信 17861405320,歡迎拉你進大佬群

一、基數是啥?

Cardinality指的就是MySQL表中某一列的不同值的數量。

如果這一類是唯一索引,那基數 = 行數。

如果這一列是sex,列舉型別只有男女,那它是基數就是2

Cardinality越高,列就越有成為索引的價值。MySQL執行計劃也會基於Cardinality選擇索引。

通過下面的方式可以看到表中各列的基數。

比如這個經典的例子:
有一列為sex,那對於sex列中儲存的值來說 非男即女,它的基數最大就是2。
那也就完全沒有必要為sex建立索引。因為,為了提升你基於sex的查詢速度,MySQL會為你選擇的這個新索引建立一棵全新的B+Tree。但你sex只有兩種值,對於MySQL來說,即使它為你指定的列建立了B+Tree索引,真正執行查詢時,最多進行一次二分查詢,剩下的操作只能是遍歷,所以為sex建立索引意義不大。

二、InnoDB更新基數的時機?

引數:innodb_stats_auto_recalc控制MySQL是否主動重新計算這些永續性的資訊。預設為1表示true,0表示false。
預設情況下當表中的行變化超過10%時,重新計算基數資訊。

三、基數是估算出來

基數並不會實時更新!而且它是通過取樣估算出來的值!

至於基數的公式是怎樣的,可能並不重要。

重要的是你得知道,他是通過隨機取樣資料頁的方式統計出來的一個估算值。

而且隨機取樣的頁數可以通過引數innodb_stats_persistent_sample_pages 設定,預設值是20。

這就意味著 基數值並不準確,甚至你每次計算的結果相擦還是蠻大的。

四、持久化基數

可以通過引數innodb_stats_persistent 控制是否持久化基數,預設為off。

當然你可以為一個單獨的表設定 STATS_PERSISTENT=1 那麼它的 innodb_stats_persistent將自動被啟用。

開啟它的好處是:重啟MySQL不會再重複計算這個值,加快重啟速度。

四、如何主動更新基數?

執行下面的SQL時都會觸發InnoDB更新基數(即使你並沒有意識到它會更新基數)。

所以儘量選擇一個業務低峰期

  • analyze table tableName;

如果因為取樣的數量太少了,計算的基數錯的離譜。那很可能會導致MySQL的優化器選錯索引。這是你可以將這個值適當調大。但是增加 太多可能會導致 ANALYZE TABLE執行緩慢。

反之, ANALYZE TABLE執行太慢。你可以適度調整引數innodb_stats_persistent_sample_pages 的值。但是這又可能導致基數計算的不準確。

如果沒有辦法平衡兩者的關係。可以考慮減少表中索引列的數量或限制分割槽的數量以降低 ANALYZE TABLE複雜性。表的主鍵中的列數也很重要,因為主鍵列被附加到每個非唯一索引中。

參考:

https://dev.mysql.com/doc/refman/5.7/en/innodb-persistent-stats.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-analyze-table-complexity.html

相關文章