成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一直傻傻分不清 count(*) count(id) count(1) 這次終于整明白了

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
對(duì)于 select count(1) from user; 這個(gè)查詢來(lái)說(shuō),InnoDB 引擎會(huì)去找到一個(gè)最小的索引樹去遍歷(不一定是主鍵索引),但是不會(huì)讀取數(shù)據(jù),而是讀到一個(gè)葉子節(jié)點(diǎn),就返回 1,最后將結(jié)果累加。

聲明:以下討論基于 InnoDB 存儲(chǔ)引擎,MyISAM 因?yàn)榍闆r特殊我在文末會(huì)單獨(dú)說(shuō)一下。

先說(shuō)結(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è)主鍵索引。

我們來(lái)用兩種方式統(tǒng)計(jì)一下表中的記錄數(shù),如下:

圖片圖片

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

再來(lái)看另外兩個(gè)統(tǒng)計(jì):

圖片圖片

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

可以看出,用 id 來(lái)統(tǒng)計(jì),也有一丟丟優(yōu)勢(shì)。松哥這里因?yàn)闇y(cè)試數(shù)據(jù)樣板比較小,所以效果不明顯,小伙伴們可以加大測(cè)試數(shù)據(jù)量,那么這種差異會(huì)更加明顯。

那么到底是什么原因造成的這種差異,接下來(lái)我們就來(lái)簡(jiǎn)單分析一下。

2. explain 分析

我們先用 explain 來(lái)看下這幾個(gè) SQL 不同的執(zhí)行計(jì)劃:

圖片圖片

可以看到,前三個(gè)統(tǒng)計(jì)方式的執(zhí)行計(jì)劃是一樣的,后面兩個(gè)是一樣的。

我這里和大家比較下 explain 中的不同項(xiàng):

  • type:前三個(gè)的 type 值為 index,表示全索引掃描,就是把整個(gè)索引過(guò)一遍就行(注意是索引不是整個(gè)表);后兩個(gè)的 type 值為 all,表示全表掃描,即不會(huì)使用索引。
  • key:這個(gè)表示 MySQL 決定采用哪個(gè)索引來(lái)優(yōu)化對(duì)該表的訪問(wèn),PRIMARY 表示利用主鍵索引,NULL 表示不用索引。
  • key_len:這個(gè)表示 MySQL 使用的鍵長(zhǎng)度,因?yàn)槲覀兊闹麈I類型是 INT 且非空,所以值為 4。
  • Extra:這個(gè)中的 Using index 表示優(yōu)化器只需要通過(guò)訪問(wèn)索引就可以獲取到需要的數(shù)據(jù)(不需要回表)。

通過(guò) explain 我們其實(shí)也能大概看出來(lái)前三種統(tǒng)計(jì)方式的執(zhí)行效率是要高一些的(因?yàn)橛玫搅怂饕竺鎯煞N的統(tǒng)計(jì)效率相對(duì)來(lái)說(shuō)要低一些的(沒(méi)用索引,需要全表掃描)。

僅有上面的分析還不夠,我們?cè)賮?lái)從原理角度來(lái)分析一下。

3. 原理分析

3.1 主鍵索引與普通索引

在開始原理分析以前,我想先帶領(lǐng)大家看一下 B+ 樹,這對(duì)于我們理解接下來(lái)的內(nèi)容有重要作用。

大家都知道,InnoDB 中索引的存儲(chǔ)結(jié)構(gòu)都是 B+ 樹,主鍵索引和普通索引的存儲(chǔ)又有所不同,如下圖表示主鍵索引:

圖片圖片

可以看到,在主鍵索引中,葉子結(jié)點(diǎn)保存了每一行的數(shù)據(jù)。

而在普通索引中,葉子結(jié)點(diǎn)保存的是主鍵值,當(dāng)我們使用普通索引去搜索數(shù)據(jù)的時(shí)候,先在葉子結(jié)點(diǎn)中找到主鍵,再拿著主鍵去主鍵索引中查找數(shù)據(jù),相當(dāng)于做了兩次查找,這也就是我們平常所說(shuō)的回表操作。

3.2 原理分析

不知道小伙伴們有沒(méi)有注意過(guò),我們學(xué)習(xí) MySQL 的時(shí)候,count 函數(shù)是歸在聚合函數(shù)那一類的,就是 avg、sum 等,count 函數(shù)和這些歸在一起,說(shuō)明它也是一個(gè)聚合函數(shù)。

既然是聚合函數(shù),那么就需要對(duì)返回的結(jié)果集進(jìn)行一行行的判斷,這里就涉及到一個(gè)問(wèn)題,返回的結(jié)果是啥?我們分別來(lái)看:

對(duì)于 select count(1) from user; 這個(gè)查詢來(lái)說(shuō),InnoDB 引擎會(huì)去找到一個(gè)最小的索引樹去遍歷(不一定是主鍵索引),但是不會(huì)讀取數(shù)據(jù),而是讀到一個(gè)葉子節(jié)點(diǎn),就返回 1,最后將結(jié)果累加。

對(duì)于 select count(id) from user;  這個(gè)查詢來(lái)說(shuō),InnoDB 引擎會(huì)遍歷整個(gè)主鍵索引,然后讀取 id 并返回,不過(guò)因?yàn)?id 是主鍵,就在 B+ 樹的葉子節(jié)點(diǎn)上,所以這個(gè)過(guò)程不會(huì)涉及到隨機(jī) IO(并不需要回表等操作去數(shù)據(jù)頁(yè)拿數(shù)據(jù)),性能也是 OK 的。

對(duì)于 select count(username) from user;  這個(gè)查詢來(lái)說(shuō),InnoDB 引擎會(huì)遍歷整張表做全表掃描,讀取每一行的 username 字段并返回,如果 username 在定義時(shí)候設(shè)置了 not null,那么直接統(tǒng)計(jì) username 的個(gè)數(shù);如果 username 在定義的時(shí)候沒(méi)有設(shè)置 not null,那么就先判斷一下 username 是否為空,然后再統(tǒng)計(jì)。

最后再來(lái)說(shuō)說(shuō) select count(*) from user; ,這個(gè) SQL 的特殊之處在于它被 MySQL 優(yōu)化過(guò),當(dāng) MySQL 看到 count(*) 就知道你是想統(tǒng)計(jì)總記錄數(shù),就會(huì)去找到一個(gè)最小的索引樹去遍歷,然后統(tǒng)計(jì)記錄數(shù)。

因?yàn)橹麈I索引(聚集索引)的葉子節(jié)點(diǎn)是數(shù)據(jù),而普通索引的葉子節(jié)點(diǎn)則是主鍵值,所以普通索引的索引樹要小一些。然而在上文的案例中,我們只有主鍵索引,所以最終使用的就是主鍵索引。

現(xiàn)在,如果我修改上面的表,為 username 字段也添加索引,然后我們?cè)賮?lái)看 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í)行起來(lái)是非常快的,那是因?yàn)?MyISAM 把表中的行數(shù)直接存在磁盤中了,需要的時(shí)候直接讀取出來(lái)就行了,所以非常快。

MyISAM 引擎之所以這樣做,主要是因?yàn)樗遣恢С质聞?wù)的,所以它的統(tǒng)計(jì)實(shí)際上就非常容易,添加一行記錄一行就行了。

而我們常用的 InnoDB 卻不能這樣做!為啥?因?yàn)?InnoDB 支持事務(wù)!為了支持事務(wù),InnoDB 引入了 MVCC 多版本并發(fā)控制,所以在數(shù)據(jù)讀取的時(shí)候可能會(huì)有臟讀、幻讀以及不可重復(fù)讀等問(wèn)題,具體可以參考 關(guān)于幻讀,該捋清楚了! 一文。

所以,InnoDB 需要將每一行數(shù)據(jù)拿出來(lái),判斷該行數(shù)據(jù)對(duì)當(dāng)前會(huì)話是否可見(jiàn),如果可見(jiàn),就統(tǒng)計(jì)該行數(shù)據(jù),否則不予統(tǒng)計(jì)。

當(dāng)然,MySQL 中的 MVCC 實(shí)際上是一個(gè)非常宏大的話題,松哥以后有空了再和大家詳細(xì)介紹 MVCC。

責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2019-07-05 16:26:06

MySQLcount(1)count(*)

2023-04-03 07:23:06

Java線程通信

2024-06-04 00:00:20

數(shù)據(jù)庫(kù)

2021-12-16 11:41:19

MySQL 數(shù)據(jù)InnoDB

2021-08-04 09:00:55

閉包Go調(diào)用

2022-03-31 16:47:30

mysqlcount面試官

2022-05-05 13:54:37

SPI機(jī)制APISPI

2021-03-10 08:56:37

Zookeeper

2021-01-22 08:37:02

二進(jìn)制Binary SemaReentrant L

2021-03-23 10:45:23

CookieSession前端

2021-10-06 23:31:45

HibernateJPASpring Data

2021-05-09 21:57:08

數(shù)據(jù)倉(cāng)庫(kù)Olap

2020-10-26 07:02:11

ConcurrentH存儲(chǔ)

2020-09-29 06:44:28

Redis延時(shí)隊(duì)列

2020-12-03 09:05:38

SQL代碼方案

2025-05-29 01:00:00

數(shù)據(jù)架構(gòu)大數(shù)據(jù)數(shù)據(jù)湖

2021-08-02 12:50:45

sessiontokenJava

2024-02-29 09:08:56

Encoding算法加密

2021-01-13 08:10:26

接口IEnumeratorIEnumerable

2022-05-15 21:52:04

typeTypeScriptinterface
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲乱码一区二区 | 亚洲最大成人综合 | 蜜臀网 | 精品国产乱码久久久久久丨区2区 | 欧美看片 | 亚洲精品久久久久久久久久久 | 精品久久久久久亚洲精品 | 日本不卡免费新一二三区 | 国产精品一区二区在线 | 成人h视频在线 | 国产在线1| 亚洲另类自拍 | 日韩国产精品一区二区三区 | 国产视频在线一区二区 | 国产激情在线播放 | 成人免费视频在线观看 | 精国产品一区二区三区四季综 | 国产欧美日韩综合精品一区二区 | 日本久久久一区二区三区 | 国产成人精品免费视频大全最热 | 欧美日韩综合精品 | 国产区视频在线观看 | 精品欧美一区二区中文字幕视频 | 国产一区二区精品在线 | 精品在线播放 | 国产在线一区二区三区 | 成人一区二区三区 | 精品一区在线看 | 日韩中文字幕 | 欧美日韩网站 | 欧美另类日韩 | 久久久免费精品 | 久久亚洲视频网 | 午夜性视频 | 国产午夜精品一区二区三区 | 亚洲乱码一区二区三区在线观看 | 国产视频久久久久 | 2023亚洲天堂 | 欧美日韩一区二区视频在线观看 | 欧美另类视频在线 | 亚洲一区二区三区在线播放 |