国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數(shù)據(jù)庫 > MySQL > 正文

MySQL中的count 和count 哪種更快

2024-07-24 12:34:13
字體:
供稿:網(wǎng)友
  這篇文章主要講解了“MySQL中的count(*)和count(1)哪個(gè)更快”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“MySQL中的count(*)和count(1)哪個(gè)更快”吧!
 
  聲明:以下討論基于 InnoDB 存儲引擎,MyISAM 因?yàn)榍闆r特殊我在文末會單獨(dú)說一下。
 
  先說結(jié)論:這兩個(gè)性能差別不大。
 
  1.實(shí)踐
  我準(zhǔn)備了一張有 100W 條數(shù)據(jù)的表,表結(jié)構(gòu)如下:
 
  CREATE TABLE `user` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `username` varchar(255) DEFAULT NULL,
    `address` varchar(255) DEFAULT NULL,
    `password` varchar(255) DEFAULT NULL,
    PRIMARY KEY (`id`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  可以看到,有一個(gè)主鍵索引。
 
  我們來用兩種方式統(tǒng)計(jì)一下表中的記錄數(shù),

  可以看到,兩條 SQL 的執(zhí)行效率其實(shí)差不多,都是 0.14s。
 
  id 是主鍵,username 以及 address 則是普通字段。
 
  可以看出,用 id 來統(tǒng)計(jì),也有一丟丟優(yōu)勢。松哥這里因?yàn)闇y試數(shù)據(jù)樣板比較小,所以效果不明顯,小伙伴們可以加大測試數(shù)據(jù)量,那么這種差異會更加明顯。
 
  那么到底是什么原因造成的這種差異,接下來我們就來簡單分析一下。
 
  2. explain 分析
  我們先用 explain 來看下這幾個(gè) SQL 不同的執(zhí)行計(jì)劃:
  
  可以看到,前三個(gè)統(tǒng)計(jì)方式的執(zhí)行計(jì)劃是一樣的,后面兩個(gè)是一樣的。
 
  我這里和大家比較下 explain 中的不同項(xiàng):
 
  type:前三個(gè)的 type 值為 index,表示全索引掃描,就是把整個(gè)索引過一遍就行(注意是索引不是整個(gè)表);后兩個(gè)的 type 值為 all,表示全表掃描,即不會使用索引。
  key:這個(gè)表示 MySQL 決定采用哪個(gè)索引來優(yōu)化對該表的訪問,PRIMARY 表示利用主鍵索引,NULL 表示不用索引。
  key_len:這個(gè)表示 MySQL 使用的鍵長度,因?yàn)槲覀兊闹麈I類型是 INT 且非空,所以值為 4。
  Extra:這個(gè)中的 Using index 表示優(yōu)化器只需要通過訪問索引就可以獲取到需要的數(shù)據(jù)(不需要回表)。
  通過 explain 我們其實(shí)也能大概看出來前三種統(tǒng)計(jì)方式的執(zhí)行效率是要高一些的(因?yàn)橛玫搅怂饕竺鎯煞N的統(tǒng)計(jì)效率相對來說要低一些的(沒用索引,需要全表掃描)。
 
  僅有上面的分析還不夠,我們再來從原理角度來分析一下。
 
  3. 原理分析
  3.1 主鍵索引與普通索引
 
  在開始原理分析以前,我想先帶領(lǐng)大家看一下 B+ 樹,這對于我們理解接下來的內(nèi)容有重要作用。
 
  大家都知道,InnoDB 中索引的存儲結(jié)構(gòu)都是 B+ 樹(至于什么是 B+ 樹,和 B 樹有什么區(qū)別,這個(gè)本文就不討論了,這兩個(gè)單獨(dú)都能整出來一篇文章),主鍵索引和普通索引的存儲又有所不同,如下圖表示主鍵索引:
  
  可以看到,在主鍵索引中,葉子結(jié)點(diǎn)保存了每一行的數(shù)據(jù)。
 
  而在普通索引中,葉子結(jié)點(diǎn)保存的是主鍵值,當(dāng)我們使用普通索引去搜索數(shù)據(jù)的時(shí)候,先在葉子結(jié)點(diǎn)中找到主鍵,再拿著主鍵去主鍵索引中查找數(shù)據(jù),相當(dāng)于做了兩次查找,這也就是我們平常所說的回表操作。
 
  3.2 原理分析
 
  不知道小伙伴們有沒有注意過,我們學(xué)習(xí) MySQL 的時(shí)候,count 函數(shù)是歸在聚合函數(shù)那一類的,就是 avg、sum 等,count 函數(shù)和這些歸在一起,說明它也是一個(gè)聚合函數(shù)。
 
  既然是聚合函數(shù),那么就需要對返回的結(jié)果集進(jìn)行一行行的判斷,這里就涉及到一個(gè)問題,返回的結(jié)果是啥?我們分別來看:
 
  對于 select count(1) from user; 這個(gè)查詢來說,InnoDB 引擎會去找到一個(gè)最小的索引樹去遍歷(不一定是主鍵索引),但是不會讀取數(shù)據(jù),而是讀到一個(gè)葉子節(jié)點(diǎn),就返回 1,最后將結(jié)果累加。
 
  對于 select count(id) from user;  這個(gè)查詢來說,InnoDB 引擎會遍歷整個(gè)主鍵索引,然后讀取 id 并返回,不過因?yàn)?id 是主鍵,就在 B+ 樹的葉子節(jié)點(diǎn)上,所以這個(gè)過程不會涉及到隨機(jī) IO(并不需要回表等操作去數(shù)據(jù)頁拿數(shù)據(jù)),性能也是 OK 的。
 
  對于 select count(username) from user;  這個(gè)查詢來說,InnoDB 引擎會遍歷整張表做全表掃描,讀取每一行的 username 字段并返回,如果 username 在定義時(shí)候設(shè)置了 not null,那么直接統(tǒng)計(jì) username 的個(gè)數(shù);如果 username 在定義的時(shí)候沒有設(shè)置 not null,那么就先判斷一下 username 是否為空,然后再統(tǒng)計(jì)。
 
  最后再來說說 select count(*) from user; ,這個(gè) SQL 的特殊之處在于它被 MySQL 優(yōu)化過,當(dāng) MySQL 看到 count(*) 就知道你是想統(tǒng)計(jì)總記錄數(shù),就會去找到一個(gè)最小的索引樹去遍歷,然后統(tǒng)計(jì)記錄數(shù)。
 
  因?yàn)橹麈I索引(聚集索引)的葉子節(jié)點(diǎn)是數(shù)據(jù),而普通索引的葉子節(jié)點(diǎn)則是主鍵值,所以普通索引的索引樹要小一些。然而在上文的案例中,我們只有主鍵索引,所以最終使用的就是主鍵索引。
 
  現(xiàn)在,如果我修改上面的表,為 username 字段也添加索引,然后我們再來看 explain select count(*) from user; 的執(zhí)行計(jì)劃:
 
  可以看到,此時(shí)使用的索引就是 username 索引了,和我們前面的分析結(jié)果是一致的。
 
  從上面的描述中我們就可以看出,第一個(gè)查詢性能最高,第二個(gè)次之(因?yàn)樾枰x取 id 并返回),第三個(gè)最差(因?yàn)樾枰頀呙瑁谒膫€(gè)的查詢性能則接近第一個(gè)。
 
  4. MyISAM 呢?
  可能有小伙伴知道,MyISAM 引擎中的 select count(*) from user; 操作執(zhí)行起來是非常快的,那是因?yàn)?MyISAM 把表中的行數(shù)直接存在磁盤中了,需要的時(shí)候直接讀取出來就行了,所以非常快。
 
  MyISAM 引擎之所以這樣做,主要是因?yàn)樗遣恢С质聞?wù)的,所以它的統(tǒng)計(jì)實(shí)際上就非常容易,添加一行記錄一行就行了。
 
  而我們常用的 InnoDB 卻不能這樣做!為啥?因?yàn)?InnoDB 支持事務(wù)!為了支持事務(wù),InnoDB 引入了 MVCC 多版本并發(fā)控制,所以在數(shù)據(jù)讀取的時(shí)候可能會有臟讀、幻讀以及不可重復(fù)讀等問題,
 
  感謝各位的閱讀,以上就是“MySQL中的count(*)和count(1)哪個(gè)更快”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對MySQL中的count(*)和count(1)哪個(gè)更快這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。

(編輯:武林網(wǎng))

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 师宗县| 禹州市| 永定县| 宣汉县| 监利县| 怀仁县| 普安县| 永城市| 琼结县| 商洛市| 彩票| 商都县| 龙口市| 招远市| 鄂托克前旗| 盘山县| 岳西县| 双桥区| 湘乡市| 梧州市| 仪征市| 乌恰县| 曲阜市| 沂南县| 石门县| 凤庆县| 镇江市| 嘉荫县| 陆丰市| 石柱| 昔阳县| 张家川| 于都县| 新宁县| 永春县| 微博| 三穗县| 梅州市| 肥东县| 雷波县| 阿勒泰市|