MySQL中count是怎样执行的?———count(1),count(id),count(非索引列),count(二级索引列)的分析
文章目錄
- 1. 前言
- 2. 建表
- 3. count是怎么樣執行的?
- 4. count(1),count(id),count(非索引列),count(二級索引列)的分析
1. 前言
??相信在此之前,很多人都只是記憶,沒去理解,只知道count(*)、count(1)包括了所有行,在統計結果的時候,不會忽略列值為NULL,count(列名)只統計列名那一列,在統計結果的時候,會忽略列值為NULL的記錄。
??下面就從原理上給大家分析一下。
2. 建表
和前面一樣,用的同一個表,表中有將近10W條數據
CREATE TABLE demo_info(id INT NOT NULL auto_increment,key1 VARCHAR(100),key2 INT,key3 VARCHAR(100),key_part1 VARCHAR(100),key_part2 VARCHAR(100),key_part3 VARCHAR(100),common_field VARCHAR(100),PRIMARY KEY (id),KEY idx_key1 (key1),UNIQUE KEY uk_key2 (key2),KEY idx_key3 (key3),KEY idx_key_part(key_part1, key_part2, key_part3) )ENGINE = INNODB CHARSET=utf8mb4;3. count是怎么樣執行的?
經常會看到這樣的例子:
當你需要統計表中有多少數據的時候,會經常使用如下語句
??由于聚集索引和非聚集索引中的記錄是一一對應的,而非聚集索引記錄中包含的列(索引列+主鍵id)是少于聚集索引(所有列)記錄的,所以同樣數量的非聚集索引記錄比聚集索引記錄占用更少的存儲空間。如果我們使用非聚集索引執行上述查詢,即統計一下非聚集索引uk_key2中共有多少條記錄,是比直接統計聚集索引中的記錄數節省很多I/O成本。所以優化器會決定使用非聚集索引uk_key2執行上述查詢。
注意:這里已經驗證過了,uk_key2比其他索引成本更低。 詳情可見MySQL查詢為什么選擇使用這個索引?——基于MySQL 8.0.22索引成本計算
分析一下執行計劃
在執行上述查詢時,server層會維護一個名叫count的變量,然后:
-
server層向InnoDB要第一條記錄。
-
InnoDB找到uk_key2的第一條二級索引記錄,并返回給server層(注意:由于此時只是統計記錄數量,所以并不需要回表)。
-
由于count函數的參數是*,MySQL會將*當作常數0處理。由于0并不是NULL,server層給count變量加1。
-
server層向InnoDB要下一條記錄。
-
InnoDB通過二級索引記錄的next_record屬性找到下一條二級索引記錄,并返回給server層。
-
server層繼續給count變量加1。
-
重復上述過程,直到InnoDB向server層返回沒記錄可查的消息。
-
server層將最終的count變量的值發送到客戶端。
4. count(1),count(id),count(非索引列),count(二級索引列)的分析
來看看count(1)
SELECT COUNT(1) FROM demo_info;執行計劃和count(*)一樣
??對于count(*)、count(1)或者任意的count(常數)來說,讀取哪個索引的記錄其實并不重要,因為server層只關心存儲引擎是否讀到了記錄,而并不需要從記錄中提取指定的字段來判斷是否為NULL。所以優化器會使用占用存儲空間最小的那個索引來執行查詢。
再看一下count(id):
explain SELECT COUNT(id) FROM demo_info;??對于count(id)來說,由于id是主鍵,不論是聚集索引記錄,還是任意一個二級索引記錄中都會包含主鍵字段,所以其實讀取任意一個索引中的記錄都可以獲取到id字段,此時優化器也會選擇占用存儲空間最小的那個索引來執行查詢。
再看一下count(非索引列)
explain select count(common_field) from demo_info??對于count(非索引列)來說,優化器選擇全表掃描,說明只能在聚集索引的葉子結點順序掃描。
請確認你理解了全表掃描,它是順序掃描聚集索引的所有葉子結點并判斷。
??而對于其他二級索引列,count(二級索引列),優化器只能選擇包含我們指定的列的索引去執行查詢,只能去指定非聚集索引的B+樹掃描 ,可能導致優化器選擇的索引掃描代價并不是最小。
綜上所述:
??對于count(*)、count(常數)、count(主鍵)形式的count函數來說,優化器可以選擇掃描成本最小的索引執行查詢,從而提升效率,它們的執行過程是一樣的,只不過在判斷表達式是否為NULL時選擇不同的判斷方式,這個判斷為NULL的過程的代價可以忽略不計,所以我們可以認為count(*)、count(常數)、count(主鍵)所需要的代價是相同的。
??而對于count(非索引列)來說,優化器選擇全表掃描,說明只能在聚集索引的葉子結點順序掃描。
??count(二級索引列)只能選擇包含我們指定的列的索引去執行查詢,可能導致優化器選擇的索引執行的代價并不是最小。
??其實上述這些區別就是因為非聚集索引記錄比聚集索引記錄占用更少的存儲空間,減少更多I/O成本,所以優化器才有了不同索引的選擇,僅此而已。
歡迎一鍵三連~
有問題請留言,大家一起探討學習
----------------------Talk is cheap, show me the code-----------------------
總結
以上是生活随笔為你收集整理的MySQL中count是怎样执行的?———count(1),count(id),count(非索引列),count(二级索引列)的分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一句话点评国内在产主流A级车
- 下一篇: RGB,CMY(K),YUV,YIQ,Y