count()聚合函數正確用法

count()聚合計算

  count()是聚合函數,對於返回的結果集,一行行地判斷,累計值加1,最後返回累計值,count(*)、count(主鍵ID)和count(1)表示返回知足條件的結果集的總行數。mysql

count()聚合函數統計非NULL與NULL值的區別:sql

  一、count(字段)不統計NULL記錄,即表示知足條件的數據行裏參數字段不爲NULL的行函數

  二、count(1)和count(*)會記錄NULL值性能

count(主鍵ID)、count(字段)、count(1)、count(*)的區別和性能差別(分析性能差異的原則)
  一、server層要什麼就給什麼 
  二、InnoDB只給必要的值
  三、如今的優化器對count(*)的取行數作了優化,其餘沒有作優化
 
count(主鍵ID)比count(1)慢的緣由
  對於 count(主鍵 ID) 來講,InnoDB 引擎會遍歷主鍵索引樹,把每一行的ID值取出來,返回給server層,server層拿到ID後,判斷是不可能爲空的,按行累加加1,最後返回累計值。
  對於count(1),InnoDB引擎會掃描主鍵索引樹,但不取值,server層對於返回的每一行,按行累計加1,判斷不可能爲NULL,返回累計值。
  從InnoDB引擎層返回ID會涉及到解析數據行、拷貝字段值的操做,所以count(主鍵 ID)執行要比count(1)執行慢。
 
count(字段)
  一、若是這個字段定義爲not null的話,一行行地從記錄裏面讀出這個字段,判斷不能爲null,按行累計加1
  二、若是這個字段定義容許爲null,一行行地從記錄裏面讀出這個字段,執行的時候還要判斷是否爲null,不爲null的按行累計加1,返回累加值
  
count(主鍵id)走主鍵索引的時候效率較count(*)差的緣由?
  平時咱們檢索一列的時候,基本上等值或範圍查詢,那麼索引基數大的索引必然效率很高(符合走主鍵索引查找速度最快的原則)。
  可是在作count(*)的時候並無檢索具體的一行或者一個範圍,那麼選擇基數小的索引對count操做效率會更高。在作count操做的時候,mysql會遍歷每一個葉子節點,因此基數越小,效率越高。mysql非聚簇索引葉子節點保存指向主鍵ID的指針,因此須要檢索兩遍索引。可是這裏相對於遍歷主鍵索引,即便檢索兩遍索引效率也比單純的檢索主鍵索引快。
  Innodb是索引組織表,主鍵索引樹的葉子節點是數據,而普通索引樹的葉子節點是主鍵值,索引普通索引樹小不少,索引長度越小樹的大小就越小。
 
MyISAM與InnoDB,正如在不一樣的存儲引擎中,count(*)函數的執行是不一樣的
  在MyISAM存儲引擎中,count()函數是直接讀取數據表保存的行記錄數並返回,效率很高,可是若是添加了where條件的話,MyISAM表也不能返回得很快。
  在InnoDB存儲引擎中,count(*)函數是先從內存中讀取表中的數據到內存緩衝區,而後掃描全表得到行記錄數。在使用count函數中加上where條件時,在兩個存儲引擎中的效果是同樣的,都會掃描全表計算某字段有值項的次數。
count(*)中關於select count(*) from tab_name幾種不走索引和走那種索引情景分析
CREATE TABLE `t1` (
  `c1` varchar(30) NOT NULL,
  `c2` varchar(20) NOT NULL,
  `c3` varchar(40) NOT NULL,
  `c4` varchar(10) DEFAULT NULL)
ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ceshi_count'
一、表中沒有任何索引(表也沒有主鍵)
mysql> explain select count(*) from t1;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |    1 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.01 sec)
二、表有主鍵則執行主鍵索引全掃描
mysql> alter table t1 add primary key (c1);
Query OK, 0 rows affected (0.16 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select count(*) from t1;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key    | key_len | ref  | rows | Extra      |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | index | NULL          | PRIMARY | 92      | NULL |    1 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
三、表有二級索引,則使用二級索引key_len最小的索引進行掃描,儘管這個二級索引的key_len的值大於主鍵,都使用二級索引
mysql> alter table t1 add index idx_c3(c3);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select count(*) from t1;
+----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key    | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | index | NULL          | idx_c3 | 122     | NULL |    1 | Using index |
+----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+
1 row in set (0.00 sec)

四、表有多個二級索引,則使用key_len小的二級索引進行掃描優化

mysql> alter table t1 add index idx_t1_c4(c4);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select count(*) from t1;
+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows | Extra      |
+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | index | NULL          | idx_t1_c4 | 33      | NULL |    1 | Using index |
+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
1 row in set (0.00 sec)
取錶行數的幾種方式
  一、count(*)取行數
  二、經過infomation_schema能夠快速拿到表的count值,但不是一個準確的值,經過show table status like 'tab_name'查找到的table rows是經過採樣方式獲得行數,它的偏差率達到了40到50%,
  三、MyISAM會存儲具體的行數(可能由於myISAM事務要加表鎖,才這樣設計),InnoDB則須要進行全表掃描
相關文章
相關標籤/搜索