納尼?MySQL 中 count(*) 比 count(1) 快?

      網友投稿 575 2025-04-01

      今天有人跟我講 Mysql 中 count(1) 比 count(*) 快,這能忍?必須得和他掰扯掰扯。

      聲明:以下討論基于 InnoDB 存儲引擎,MyISAM 因為情況特殊我在文末會單獨說一下。

      先說結論:這兩個性能差別不大。

      1.實踐

      我準備了一張有 100W 條數據的表,表結構如下:

      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;

      1

      2

      3

      4

      5

      6

      7

      可以看到,有一個主鍵索引。

      我們來用兩種方式統計一下表中的記錄數,如下:

      可以看到,兩條 SQL 的執行效率其實差不多,都是 0.14s。

      再來看另外兩個統計:

      id 是主鍵,username 以及 address 則是普通字段。

      可以看出,用 id 來統計,也有一丟丟優勢。松哥這里因為測試數據樣板比較小,所以效果不明顯,小伙伴們可以加大測試數據量,那么這種差異會更加明顯。

      那么到底是什么原因造成的這種差異,接下來我們就來簡單分析一下。

      2. explain 分析

      我們先用 explain 來看下這幾個 SQL 不同的執行計劃:

      可以看到,前三個統計方式的執行計劃是一樣的,后面兩個是一樣的。

      我這里和大家比較下 explain 中的不同項:

      type:前三個的 type 值為 index,表示全索引掃描,就是把整個索引過一遍就行(注意是索引不是整個表);后兩個的 type 值為 all,表示全表掃描,即不會使用索引。

      key:這個表示 Mysql 決定采用哪個索引來優化對該表的訪問,PRIMARY 表示利用主鍵索引,NULL 表示不用索引。

      key_len:這個表示 MySQL 使用的鍵長度,因為我們的主鍵類型是 INT 且非空,所以值為 4。

      Extra:這個中的 Using index 表示優化器只需要通過訪問索引就可以獲取到需要的數據(不需要回表)。

      通過 explain 我們其實也能大概看出來前三種統計方式的執行效率是要高一些的(因為用到了索引),而后面兩種的統計效率相對來說要低一些的(沒用索引,需要全表掃描)。

      僅有上面的分析還不夠,我們再來從原理角度來分析一下。

      3. 原理分析

      3.1 主鍵索引與普通索引

      在開始原理分析以前,我想先帶領大家看一下 B+ 樹,這對于我們理解接下來的內容有重要作用。

      大家都知道,InnoDB 中索引的存儲結構都是 B+ 樹(至于什么是 B+ 樹,和 B 樹有什么區別,這個本文就不討論了,這兩個單獨都能整出來一篇文章),主鍵索引和普通索引的存儲又有所不同,如下圖表示主鍵索引:

      可以看到,在主鍵索引中,葉子結點保存了每一行的數據。

      而在普通索引中,葉子結點保存的是主鍵值,當我們使用普通索引去搜索數據的時候,先在葉子結點中找到主鍵,再拿著主鍵去主鍵索引中查找數據,相當于做了兩次查找,這也就是我們平常所說的回表操作。

      3.2 原理分析

      不知道小伙伴們有沒有注意過,我們學習 MySQL 的時候,count 函數是歸在聚合函數那一類的,就是 avg、sum 等,count 函數和這些歸在一起,說明它也是一個聚合函數。

      既然是聚合函數,那么就需要對返回的結果集進行一行行的判斷,這里就涉及到一個問題,返回的結果是啥?我們分別來看:

      對于 select count(1) from user; 這個查詢來說,InnoDB 引擎會去找到一個最小的索引樹去遍歷(不一定是主鍵索引),但是不會讀取數據,而是讀到一個葉子節點,就返回 1,最后將結果累加。

      對于 select count(id) from user; 這個查詢來說,InnoDB 引擎會遍歷整個主鍵索引,然后讀取 id 并返回,不過因為 id 是主鍵,就在 B+ 樹的葉子節點上,所以這個過程不會涉及到隨機 IO(并不需要回表等操作去數據頁拿數據),性能也是 OK 的。

      對于 select count(username) from user; 這個查詢來說,InnoDB 引擎會遍歷整張表做全表掃描,讀取每一行的 username 字段并返回,如果 username 在定義時候設置了 not null,那么直接統計 username 的個數;如果 username 在定義的時候沒有設置 not null,那么就先判斷一下 username 是否為空,然后再統計。

      最后再來說說 select count(*) from user; ,這個 SQL 的特殊之處在于它被 MySQL 優化過,當 MySQL 看到 count(*) 就知道你是想統計總記錄數,就會去找到一個最小的索引樹去遍歷,然后統計記錄數。

      納尼?MySQL 中 count(*) 比 count(1) 快?

      因為主鍵索引(聚集索引)的葉子節點是數據,而普通索引的葉子節點則是主鍵值,所以普通索引的索引樹要小一些。然而在上文的案例中,我們只有主鍵索引,所以最終使用的就是主鍵索引。

      現在,如果我修改上面的表,為 username 字段也添加索引,然后我們再來看 explain select count(*) from user; 的執行計劃:

      可以看到,此時使用的索引就是 username 索引了,和我們前面的分析結果是一致的。

      從上面的描述中我們就可以看出,第一個查詢性能最高,第二個次之(因為需要讀取 id 并返回),第三個最差(因為需要全表掃描),第四個的查詢性能則接近第一個。

      4. MyISAM 呢?

      可能有小伙伴知道,MyISAM 引擎中的 select count(*) from user; 操作執行起來是非常快的,那是因為 MyISAM 把表中的行數直接存在磁盤中了,需要的時候直接讀取出來就行了,所以非常快。

      MyISAM 引擎之所以這樣做,主要是因為它是不支持事務的,所以它的統計實際上就非常容易,添加一行記錄一行就行了。

      而我們常用的 InnoDB 卻不能這樣做!為啥?因為 InnoDB 支持事務!為了支持事務,InnoDB 引入了 MVCC 多版本并發控制,所以在數據讀取的時候可能會有臟讀、幻讀以及不可重復讀等問題,具體可以參考 https://www.bilibili.com/video/BV14L4y1B7mB 視頻。

      所以,InnoDB 需要將每一行數據拿出來,判斷該行數據對當前會話是否可見,如果可見,就統計該行數據,否則不予統計。

      當然,MySQL 中的 MVCC 實際上是一個非常宏大的話題,松哥以后有空了再和大家詳細介紹 MVCC。

      好啦,現在小伙伴們懂了吧?有問題歡迎留言討論。

      MySQL SQL

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:word表格乘法公式計算方法(word表格乘法公式計算公式)
      下一篇:修改配色方案(修改配色方案后選擇應用)
      相關文章
      久久精品亚洲中文字幕无码网站| 中文字幕专区在线亚洲| 在线日韩日本国产亚洲| 国产成人 亚洲欧洲| 亚洲愉拍一区二区三区| 亚洲人成网站看在线播放| 亚洲福利一区二区精品秒拍| 久久亚洲精品成人av无码网站| 亚洲乱码国产乱码精品精| 浮力影院亚洲国产第一页| 国产亚洲人成A在线V网站| 国产亚洲精品自在线观看| 国产成人亚洲影院在线观看| 国产午夜亚洲精品不卡电影| 免费在线观看亚洲| 亚洲无线一二三四区手机| 亚洲国产精品丝袜在线观看| www.亚洲色图.com| 亚洲国产精品第一区二区三区| 国产亚洲美女精品久久久久| 亚洲AV成人潮喷综合网| 国产精品亚洲色婷婷99久久精品| 337P日本欧洲亚洲大胆艺术图| 爱情岛论坛亚洲品质自拍视频网站 | 亚洲色精品88色婷婷七月丁香| 久久亚洲国产精品123区| 亚洲欧洲美洲无码精品VA| 亚洲色精品aⅴ一区区三区| 无码久久精品国产亚洲Av影片| 久久亚洲AV成人无码国产| 亚洲日韩中文字幕| 国产亚洲中文日本不卡二区 | 亚洲已满18点击进入在线观看| 亚洲综合精品伊人久久| 日韩欧美亚洲国产精品字幕久久久| 成人亚洲国产精品久久| a级亚洲片精品久久久久久久 | 亚洲国产一区二区三区青草影视| 亚洲网址在线观看你懂的| 亚洲最大的视频网站| 亚洲中文字幕无码久久2020|