MySQL count(*),count(1),count(field)區(qū)別、性能差異及優(yōu)化建議

count函數(shù)是用來獲取表中滿足一定條件的記錄數(shù),常見用法有三種,count(*),count(1),count(field),這三種有什么區(qū)別?在性能上有何差異?本文將通過測試案例詳細(xì)介紹和分析。

原文地址:
mytecdb.com/blogDetail.php?id=81

三者有何區(qū)別:

  • count(field)不包含字段值為NULL的記錄。
  • count(*)包含NULL記錄。
  • select(*)與select(1) 在InnoDB中性能沒有任何區(qū)別,處理方式相同。官方文檔描述如下:
    InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
1. 性能對比

通過案例來測試一下count(*),count(1),count(field)的性能差異,MySQL版本為5.7.19,測試表是一張sysbench生成的表,表名sbtest1,總記錄數(shù)2411645,如下:

CREATE TABLE sbtest1 (
id int(11) NOT NULL AUTO_INCREMENT,
k int(11) DEFAULT NULL,
c char(120) NOT NULL DEFAULT '',
pad char(60) NOT NULL DEFAULT '',
PRIMARY KEY (id),
KEY k_1 (k)
) ENGINE=InnoDB;

測試SQL語句:

select count(*) from sbtest1;
select count(1) from sbtest1;
select count(id) from sbtest1;
select count(k) from sbtest1;
select count(c) from sbtest1;
select count(pad) from sbtest1;

針對count(*)、count(1)和count(id),加了強(qiáng)制走主鍵的測試,如下:
select count(*) from sbtest1 force index(primary);
select count(1) from sbtest1 force index(primary);
select count(id) from sbtest1 force index(primary);

另外對不同的測試SQL,收集了profile,發(fā)現(xiàn)主要耗時(shí)都在Sending data這個(gè)階段,記錄Sending data值。

匯總測試結(jié)果:

類型 耗時(shí)(s) 索引 Sending data耗時(shí)(s)
count(*) 0.47 k_1 0.463624
count(1) 0.46 k_1 0.463242
count(id) 0.52 k_1 0.521618
count(*)強(qiáng)制走主鍵 0.54 primay key 0.538737
count(1)強(qiáng)制走主鍵 0.55 primary key 0.545007
count(id)強(qiáng)制走主鍵 0.60 primary key 0.598975
count(k) 0.53 k_1 0.529366
count(c) 0.81 NULL 0.813918
count(pad) 0.76 NULL 0.762040

結(jié)果分析:

  1. 從以上測試結(jié)果來看,count(*)和count(1)性能基本一樣,默認(rèn)走二級索引(k_1),性能最好,這也驗(yàn)證了count(*)和count(1)在InnoDB內(nèi)部處理方式一樣。
  2. count(id) 雖然也走二級索引(k_1),但是性能明顯低于count(*)和count(1),可能MySQL內(nèi)部在處理count(*)和count(1)時(shí)做了額外的優(yōu)化。
  3. 強(qiáng)制走主鍵索引時(shí),性能反而沒有走更小的二級索引好,InnoDB存儲引擎是索引組織表,行數(shù)據(jù)在主鍵索引的葉子節(jié)點(diǎn)上,走主鍵索引掃描時(shí),處理的數(shù)據(jù)量比二級索引更多,所以性能不及二級索引。
  4. count(c)和count(pad)沒有走索引,性能最差,但是明顯count(pad)比count(c)好,因?yàn)閜ad字段類型為char(60),小于字段c的char(120),盡管兩者性能墊底,但是字段小的性能相對更好些。
2. count(*)延伸
  • 在5.7.18版本之前,InnoDB處理select count(*) 是通過掃描聚簇索引,來獲取總記錄數(shù)。
  • 從5.7.18版本開始,InnoDB掃描一個(gè)最小的可用的二級索引來獲取總記錄數(shù),或者由SQL hint來告訴優(yōu)化器使用哪個(gè)索引。如果二級索引不存在,InnoDB將會掃描聚簇索引。

執(zhí)行select count(*)在大部分場景下性能都不會太好,尤其是表記錄數(shù)特別大的情況下,索引數(shù)據(jù)不在buffer pool里面,需要頻繁的讀磁盤,性能將更差。

3. count(*)優(yōu)化思路
  1. 一種優(yōu)化方法,是使用一個(gè)統(tǒng)計(jì)表來存儲表的記錄總數(shù),在執(zhí)行DML操作時(shí),同時(shí)更新該統(tǒng)計(jì)表。這種方法適用于更新較少,讀較多的場景,而對于高并發(fā)寫操作,性能有很大影響,因?yàn)樾枰l(fā)更新熱點(diǎn)記錄。
  2. 如果業(yè)務(wù)對count數(shù)量的精度沒有太大要求,可使用show table status中的行數(shù)作為近似值。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我因?yàn)樯眢w的原因,放棄了日更。一下子覺得輕松了好多。 日更,作為愛好就有點(diǎn)過分了。成了壓力和負(fù)擔(dān)。剛開始是這樣想的...
    成依格閱讀 244評論 0 1
  • 這個(gè)課叫短程,這個(gè)短程有三個(gè)階段。基礎(chǔ)是同理心。從一腳在岸上一腳在水中的基礎(chǔ)同心到有經(jīng)驗(yàn),高度覺察的同理心。同理心...
    余師師閱讀 2,167評論 0 3
  • 壹 在地鐵站出口,看到一個(gè)小姑娘蹲著痛哭流涕,絲毫不顧及來往的人群。地上撒滿了傳單,一看就是拉扯壞掉的手提袋被孤零...
    武漢老汪閱讀 2,221評論 0 2
  • 酸酸甜又香。吐吐剝皮瓤 子子妙中藏,顆顆琥珀光。
    藍(lán)手印zzy閱讀 397評論 4 9

友情鏈接更多精彩內(nèi)容