count(*) 的實現(xiàn)方式:
1.?MyISAM 引擎把一個表的總行數(shù)存在了磁盤上遭庶,因此執(zhí)行 count(*) 的時候會直接返回
這個數(shù)宁仔,效率很高;
2.?而 InnoDB 引擎就麻煩了峦睡,它執(zhí)行 count(*) 的時候翎苫,需要把數(shù)據(jù)一行一行地從引擎里面
讀出來,然后累積計數(shù)榨了。
這里需要注意的是煎谍,我們在這篇文章里討論的是沒有過濾條件的 count(*),如果加了
where 條件的話龙屉,MyISAM 表也是不能返回得這么快的呐粘。
為什么 InnoDB 不跟 MyISAM 一樣,也把數(shù)字存起來呢叔扼?
這是因為即使是在同一個時刻的多個查詢事哭,由于多版本并發(fā)控制(MVCC)的原因,
InnoDB 表“應該返回多少行”也是不確定的瓜富。
在保證邏輯正確的前提下鳍咱,盡量減少掃描的數(shù)據(jù)量,是數(shù)據(jù)庫系統(tǒng)設(shè)計的通用法則
之一与柑。
解決計數(shù)的方法:
1.?用緩存系統(tǒng)保存計數(shù)
存在的問題:1)計數(shù)丟失谤辜;2)計數(shù)不準確
2.?在數(shù)據(jù)庫保存計數(shù)? ----> 常用的手段
不同的 count 用法
1).?對于 count(主鍵 id) 來說
InnoDB 引擎會遍歷整張表蓄坏,把每一行的 id 值都取出來,返回給 server 層丑念。server 層拿到 id 后涡戳,判斷是不可能為空的,就按行累加脯倚。
2).?對于 count(1) 來說
InnoDB 引擎遍歷整張表渔彰,但不取值。server 層對于返回的每一行推正,放一個數(shù)字“1”進去恍涂,判斷是不可能為空的,按行累加植榕。
count(1) 執(zhí)行得要比 count(主鍵 id) 快再沧。因為從引擎返回 id 會涉及到解析數(shù)據(jù)行,以及拷貝字段值的操作尊残。
3).?對于 count(字段) 來說:
????1. 如果這個“字段”是定義為 not null 的話炒瘸,一行行地從記錄里面讀出這個字段,判斷不
????????能為 null寝衫,按行累加顷扩;
2. 如果這個“字段”定義允許為 null,那么執(zhí)行的時候竞端,判斷到有可能是 null屎即,還要把值
? ? ? ?取出來再判斷一下,不是 null 才累加事富。
4).?count(*)
? ??????并不會把全部字段取出來技俐,而是專門做了優(yōu)化,不取值统台。count(*) 肯定不是 null雕擂,按行累加。
所以結(jié)論是:按照效率排序的話
count(字段)<count(主鍵 id)<count(1))≈count(*)贱勃,盡量使用 count(*)井赌。