count(*)的實(shí)現(xiàn)方式
不同的存儲(chǔ)引擎在實(shí)現(xiàn)count(*)的方式上不同
MyISAM 引擎把一個(gè)表的總行數(shù)存在了磁盤上杖刷,因此執(zhí)行 count(*) 的時(shí)候會(huì)直接返回
這個(gè)數(shù),效率很高名船;
而 InnoDB 引擎就麻煩了止潘,它執(zhí)行 count(*) 的時(shí)候别威,需要把數(shù)據(jù)一行一行地從引擎里面
讀出來(lái)炸站,然后累積計(jì)數(shù)亡电。
如果加入了where條件,MyISAM也不可能返回那么快。
show table status
使用命令偏瓤,會(huì)返回TABLE_ROWS,但是這個(gè)數(shù)是基于采樣計(jì)數(shù)的不夠準(zhǔn)確杀怠。
區(qū)別引擎和show table status
MyISAM 表雖然 count(*) 很快,但是不支持事務(wù)厅克;
show table status 命令雖然返回很快赔退,但是不準(zhǔn)確;
InnoDB 表直接 count(*) 會(huì)遍歷全表证舟,雖然結(jié)果準(zhǔn)確硕旗,但會(huì)導(dǎo)致性能問(wèn)題。
如果用緩存系統(tǒng)存儲(chǔ)計(jì)數(shù)
存在丟失更新和數(shù)據(jù)不同步的情況女责,因?yàn)榫彺婧蛿?shù)據(jù)庫(kù)同時(shí)修改并非原子操作卵渴。
把計(jì)數(shù)放在 Redis 里面,不能夠保證計(jì)數(shù)和 MySQL 表里的數(shù)據(jù)精確一致的原因鲤竹,
是這兩個(gè)不同的存儲(chǔ)構(gòu)成的系統(tǒng)浪读,不支持分布式事務(wù),無(wú)法拿到精確一致的視圖辛藻。而把計(jì)數(shù)值也放在 MySQL 中碘橘,就解決了一致性視圖的問(wèn)題。
數(shù)據(jù)庫(kù)保存計(jì)數(shù)
- 不會(huì)丟失更新
- 同時(shí)利用事務(wù)特性吱肌,同步計(jì)數(shù)和實(shí)際表內(nèi)容
不同count用法
count語(yǔ)義痘拆,聚合函數(shù),對(duì)于返回的結(jié)果集合一行行地進(jìn)行判斷氮墨,如果count的值不為空纺蛆,計(jì)數(shù)加一,最后返回累計(jì)值规揪。
count(*)桥氏、count(主鍵 id) 和 count(1) 都表示返回滿足條件的結(jié)果集的總行數(shù);而
count(字段)猛铅,則表示返回滿足條件的數(shù)據(jù)行里面字支,參數(shù)“字段”不為 NULL 的總個(gè)數(shù)。
- count(*)奸忽,優(yōu)化器優(yōu)化了 count(*) 的語(yǔ)義為“取行數(shù)”
- count(主鍵 id)堕伪,InnoDB 引擎會(huì)遍歷整張表,把每一行的 id 值都取出來(lái)栗菜,返
回給 server 層欠雌。server 層拿到 id 后,判斷是不可能為空的疙筹,就按行累加富俄。 - count(字段)
- 如果這個(gè)“字段”是定義為 not null 的話检号,一行行地從記錄里面讀出這個(gè)字段,判斷不能為 null蛙酪,按行累加;
- 如果這個(gè)“字段”定義允許為 null翘盖,那么執(zhí)行的時(shí)候桂塞,判斷到有可能是 null,還要把值取出來(lái)再判斷一下馍驯,不是 null 才累加
- count(1) InnoDB 引擎遍歷整張表阁危,但不取值。server 層對(duì)于返回的每一
行汰瘫,放一個(gè)數(shù)字“1”進(jìn)去狂打,判斷是不可能為空的,按行累加混弥。
結(jié)論
按照效率排序的話趴乡,count(字段)<count(主鍵 id)<count(1)≈count(*),所
以我建議你蝗拿,盡量使用 count(*)晾捏。