count(1),count(*),count(主鍵) 性能對比及闢謠

前言

前段時間關於統計數量的sql問題和朋友進行了討論,網上關於這三種查詢方式說法不一,主要有以下兩種說法。

  1. count(*) = count(主鍵) > count(1)
  2. count(主鍵) > count(*) > count(1)

今天對這三種方式進行探究。

數據庫爲mysql 5.7.12,引擎爲InnoDB。

建表

CREATE TABLE `user` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `name` varchar(500) DEFAULT NULL COMMENT '姓名',
  `deleted` int(2) NOT NULL DEFAULT '1' COMMENT '邏輯刪除',
  `created_date` datetime DEFAULT NULL COMMENT '創建時間',
  `created_by` varchar(255) DEFAULT NULL,
  `update_date` datetime DEFAULT NULL,
  `update_by` varchar(255) DEFAULT NULL,
  `version` int(11) NOT NULL DEFAULT '1' COMMENT '樂觀鎖',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1502726 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='用戶表';

循環插入150萬條數據。

DROP PROCEDURE
IF
	EXISTS proc_initData;
DELIMITER $
CREATE PROCEDURE proc_initData () BEGIN
	DECLARE
		i INT DEFAULT 1;
	WHILE
			i <= 5000000 DO
			INSERT INTO user ( name, created_date, update_date )
		VALUES
			( '哈哈哈啊哈哈哈', NOW(), NOW() );
		
		SET i = i + 1;
		
	END WHILE;

END $ CALL proc_initData ();

這裏需要使用到mysql的explain關鍵字,對count(1),count(*),count(id),count(name)分別查看性能

explain select count(1) from user
explain select count(*) from user
explain select count(id) from user
explain select count(name) from user

可以看出,select count(1)、count(*)、count(id)的執行計劃是一毛一樣的。多次執行取平均值,三者的性能也是非常趨近,因此可以認爲三者性能相同。這裏我加了個count(name)進行對比,並將最後30萬條數據的name置空,可以看出性能有明顯的差別。

mysql底層對count查詢做了優化,當mysql確定count中的列名不爲空時,實際上就是在統計行數。那麼mysql內部會將count(列名)優化爲count(*) —— 出自《高性能MySQL》一書

也就是說count(1)和count(主鍵字段)還是要優化到count(*)的,而如果只是統計某個列,只要該列不爲空,無論是否爲索引,都會被優化爲count(*),因此三者性能並無任何差異。官方文檔對其也進行了解釋。

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count

至此,事實上並未解決關於這個問題的疑惑。上面的內容都在強調“Mysql”,就是說,上面的驗證可能僅對MySql有效,其他的數據庫可能未必會對count語句進行優化。因此我又通過SQLServer去驗證。

因爲我本地並沒有安裝SQLServer,因此我是直接使用公司的開發庫進行驗證,這裏不方便截圖,直接說明一下200萬條數據驗證結果。

  1. 列名爲主鍵,count(列名)會比count(1)快  
  2. 列名不爲主鍵,count(1)會比count(列名)快  
  3. 如果表多個列並且沒有主鍵,則 count(1) 的執行效率優於 count(*)  
  4. 如果有主鍵,則 select count(主鍵)的執行效率是最優的  
  5. 如果表只有一個字段,則 select count(*)最優。

可見,在SQLServer中,count(*)的性能並沒有count(主鍵)高。

結語

根據上面對兩個數據庫的驗證得出結論:不說是什麼數據庫都是耍流氓!SQL標準只提供了count這個內置函數,所有的數據庫需要遵循這個標準,但是不同的數據庫對於count的處理不同。在mysql中建議寫count(*),而在SQLServer中建議寫count(主鍵),在PostgreSql以及其他數據庫中並未對其進行驗證

發佈了28 篇原創文章 · 獲贊 32 · 訪問量 2558
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章