count(*) 優化

幾種獲取記錄數的方法

count(*):  MySQL 優化過,掃描的行數小於總記錄數。執行效率高。數據庫

count(1):  遍歷全部記錄,不取值,對每行嘗試添加一個 「1」 列,若是不爲 null,就計入累加(引擎層)。緩存

count(主鍵):  遍歷全部記錄,並把每一個記錄的 id 取出返回 Server 層判斷,將不爲 null 的計入累加。併發

count(字段):  遍歷全部記錄,並把每一個記錄的字段值取出返回 Server 層判斷,將不爲 null 的計入累加。優化

效率排序:  count(*) ≈ count(1) > count(主鍵) > count(字段)spa

除此以外,還能夠經過 " show table status like '表名' " 查看 'TABLE_ROW' 參數來獲取系統內部經過採樣估算的記錄數,但偏差會達到 40% -- 50%。blog

 

優化

使用緩存

經過上面的分析能夠知道經過 count(*) 來獲取計數已是效率最高的一種方式了, 可是若是效率仍是低呢?首先效率低確定是執行計數操做的併發量過高所致使的。而應對查詢操做最多見的優化方式就是使用緩存,可是使用緩存適用於查多寫少的場景,不過由於計數不會由於修改操做而改變,只會被增刪操做所改變,因此在增刪操做少的場景也是可使用的。可是還有另一個問題,那就是獲取計數的業務和計數自增自減的操做不能保證原子性。這樣致使查出的結果可能並不許確。排序

好比:table

有一個頁面,要顯示操做記錄的總數,同時還要顯示最近操做的 100 條記錄。那麼,這個頁面的邏輯就須要先到 Redis 裏面取出計數,再到數據表裏面取數據記錄。效率

一種是,查到的 100 行結果裏面有最新插入記錄,而 Redis 的計數裏還沒加 1;遍歷

另外一種是,查到的 100 行結果裏沒有最新插入的記錄,而 Redis 的計數裏已經加了 1。

那麼第一種狀況就會致使查詢的計數和記錄對不上,獲得的結果混亂。

 

數據庫

若是將計數結果單首創建一張表來存儲,搭配 MySQL 的可重複讀隔離級別,就能夠實現數據讀取的 "原子性" ,而且效率也會很高。

 在會話B讀取計數時就會由於會話A還未提交,因此不會讀取到會話A執行過的操做。

相關文章
相關標籤/搜索