COUNT(*)/COUNT(id)/COUNT(1)适用场景

          COUNT(*)/COUNT(id)/COUNT(1)适用场景

1.前言

    在使用任何数据库的时候,我们经常会用到类似以下三种方式获得tablename表的行数:

    SELECT COUNT(*) FROM tablename
    SELECT COUNT(id) FROM tablename(id为自增主键)
    SELECT COUNT(1) FROM tablename

    大家也会争论到底是哪种方式性能更好,每个人都有自己的一套理论。本着任何结论都有证可依的原则。本次针对这个话题进行研究和测试。

2.测试环境
    本章节描述以下内容基于哪些测试环境
2.1.硬件环境
    测试统一使用一台vmware虚拟机。
    CPU:Intel(R) Core(TM) i7-4712MQ CPU @ 2.30GHz *4
    内存:4GB
    硬盘:20GB,统一使用ext4文件系统。文件系统使用默认选项。
2.2.软件环境
    操作系统:CentOS 6.6 64位
    数据库软件: Percona-Server-server-56-5.6.25-rel73.1.el6.x86_64
2.3.数据表
    数据库macrodb中存在三张表test1、test2、test3

    这三张表的建表ddl语句是:
CREATE TABLE `test1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `sname` varchar(255) DEFAULT NULL,
  `add_timestamp` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_tst1_addtimestamp` (`add_timestamp`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test1测试表'
    
CREATE TABLE `test2` (
  `id` bigint(20) DEFAULT NULL,
  `sname` varchar(255) DEFAULT NULL,
  `add_timestamp` datetime DEFAULT NULL,
  KEY `idx_tst2_id` (`id`) USING BTREE,
  KEY `idx_tst2_adatetime` (`add_timestamp`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test2测试表没有主键'

CREATE TABLE `test3` (
  `id` bigint(20) DEFAULT NULL,
  `sname` varchar(255) DEFAULT NULL,
  `add_timestamp` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test3没有任何索引'
    循环往这三张表插入1KW条记录,其中每个表都会有10条记录add_timestamp出现NULL值。
    
    

3.测试内容:
3.1.在test1上测试
3.1.1测试COUNT(1)

--------------
explain extended select count(1) from macrodb.test1
--------------

+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key                   | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test1 | index | NULL          | idx_tst1_addtimestamp | 6       | NULL | 3363672 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(1) AS `count(1)` from `macrodb`.`test1` |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(1) from  macrodb.test1
--------------

+----------+
| count(1) |
+----------+
|  3287480 |
+----------+
1 row in set (0.46 sec)

3.1.2.测试COUNT(id)
--------------
explain extended select count(id) from macrodb.test1
--------------

+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key                   | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test1 | index | NULL          | idx_tst1_addtimestamp | 6       | NULL | 3363672 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+-------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                   |
+-------+------+-------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(`macrodb`.`test1`.`id`) AS `count(id)` from `macrodb`.`test1` |
+-------+------+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(id) from  macrodb.test1
--------------

+-----------+
| count(id) |
+-----------+
|   3287480 |
+-----------+
1 row in set (0.54 sec)

3.1.3.测试test1非组件列
--------------
explain extended select count(add_timestamp) from macrodb.test1
--------------

+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key                   | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test1 | index | NULL          | idx_tst1_addtimestamp | 6       | NULL | 3363672 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+-----------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                         |
+-------+------+-----------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(`macrodb`.`test1`.`add_timestamp`) AS `count(add_timestamp)` from `macrodb`.`test1` |
+-------+------+-----------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(add_timestamp) from  macrodb.test1
--------------

+----------------------+
| count(add_timestamp) |
+----------------------+
|              3287470 |
+----------------------+
1 row in set (0.58 sec)

3.1.4.测试COUNT(*)
--------------
explain extended select count(*) from macrodb.test1
--------------

+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key                   | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test1 | index | NULL          | idx_tst1_addtimestamp | 6       | NULL | 3363672 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+-----------------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(0) AS `count(*)` from `macrodb`.`test1` |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(*) from  macrodb.test1
--------------

+----------+
| count(*) |
+----------+
|  3287480 |
+----------+
1 row in set (0.46 sec)

3.1.5.测试带WHERE的COUNT(*)
--------------
explain extended select count(*) from macrodb.test1 where add_timestamp >'2014-01-01 00:00:00'  
--------------

+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
| id | select_type | table | type  | possible_keys         | key                   | key_len | ref  | rows    | filtered | Extra                    |
+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
|  1 | SIMPLE      | test1 | range | idx_tst1_addtimestamp | idx_tst1_addtimestamp | 6       | NULL | 1681836 |   100.00 | Using where; Using index |
+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                               |
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(0) AS `count(*)` from `macrodb`.`test1` where (`macrodb`.`test1`.`add_timestamp` > '2014-01-01 00:00:00') |
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(*) from  macrodb.test1 where add_timestamp>'2014-01-01 00:00:00'
--------------

+----------+
| count(*) |
+----------+
|  3287470 |
+----------+
1 row in set (0.77 sec)

3.1.6.测试带WHERE的COUNT(主键列)
--------------
explain extended select count(id) from macrodb.test1 where add_timestamp >'2014-01-01 00:00:00'
--------------

+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
| id | select_type | table | type  | possible_keys         | key                   | key_len | ref  | rows    | filtered | Extra                    |
+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
|  1 | SIMPLE      | test1 | range | idx_tst1_addtimestamp | idx_tst1_addtimestamp | 6       | NULL | 1681836 |   100.00 | Using where; Using index |
+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                     |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(`macrodb`.`test1`.`id`) AS `count(id)` from `macrodb`.`test1` where (`macrodb`.`test1`.`add_timestamp` > '2014-01-01 00:00:00') |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(id) from  macrodb.test1 where add_timestamp >'2014-01-01 00:00:00'
--------------

+-----------+
| count(id) |
+-----------+
|   3287470 |
+-----------+
1 row in set (0.86 sec)

3.1.7.测试带WHERE的COUNT(非主键列)
--------------
explain extended select count(add_timestamp) from macrodb.test1 where add_timestamp >'2014-01-01 00:00:00'
--------------

+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
| id | select_type | table | type  | possible_keys         | key                   | key_len | ref  | rows    | filtered | Extra                    |
+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
|  1 | SIMPLE      | test1 | range | idx_tst1_addtimestamp | idx_tst1_addtimestamp | 6       | NULL | 1681836 |   100.00 | Using where; Using index |
+----+-------------+-------+-------+-----------------------+-----------------------+---------+------+---------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                           |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(`macrodb`.`test1`.`add_timestamp`) AS `count(add_timestamp)` from `macrodb`.`test1` where (`macrodb`.`test1`.`add_timestamp` > '2014-01-01 00:00:00') |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(add_timestamp) from  macrodb.test1 where add_timestamp >'2014-01-01 00:00:00'
--------------

+----------------------+
| count(add_timestamp) |
+----------------------+
|              3287470 |
+----------------------+
1 row in set (0.78 sec)


3.2.测试test2
3.2.1.测试COUNT(1)
--------------
explain extended select count(1) from macrodb.test2
--------------

+----+-------------+-------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key                | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test2 | index | NULL          | idx_tst2_adatetime | 6       | NULL | 3274822 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(1) AS `count(1)` from `macrodb`.`test2` |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(1) from  macrodb.test2
--------------

+----------+
| count(1) |
+----------+
|  3287480 |
+----------+
1 row in set (0.81 sec)

3.2.2.测试COUNT(id)
--------------
explain extended select count(id) from macrodb.test2
--------------

+----+-------------+-------+-------+---------------+-------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key         | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+-------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test2 | index | NULL          | idx_tst2_id | 9       | NULL | 3274822 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+-------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+-------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                   |
+-------+------+-------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(`macrodb`.`test2`.`id`) AS `count(id)` from `macrodb`.`test2` |
+-------+------+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(id) from  macrodb.test2
--------------

+-----------+
| count(id) |
+-----------+
|   3287480 |
+-----------+
1 row in set (2.41 sec)

3.2.3.测试COUNT(*)
--------------
explain extended select count(*) from macrodb.test2
--------------

+----+-------------+-------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key                | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test2 | index | NULL          | idx_tst2_adatetime | 6       | NULL | 3274822 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(0) AS `count(*)` from `macrodb`.`test2` |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(*) from  macrodb.test2
--------------

+----------+
| count(*) |
+----------+
|  3287480 |
+----------+
1 row in set (0.82 sec)

3.3.测试test3
3.3.1.测试COUNT(1)
--------------
explain extended select count(1) from macrodb.test3
--------------

+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
|  1 | SIMPLE      | test3 | ALL  | NULL          | NULL | NULL    | NULL | 3285169 |   100.00 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(1) AS `count(1)` from `macrodb`.`test3` |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(1) from  macrodb.test3
--------------

+----------+
| count(1) |
+----------+
|  3287480 |
+----------+
1 row in set (1.43 sec)

3.3.2.测试COUNT(id)
--------------
explain extended select count(id) from macrodb.test3
--------------

+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
|  1 | SIMPLE      | test3 | ALL  | NULL          | NULL | NULL    | NULL | 3285169 |   100.00 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+-------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                   |
+-------+------+-------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(`macrodb`.`test3`.`id`) AS `count(id)` from `macrodb`.`test3` |
+-------+------+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(id) from  macrodb.test3
--------------

+-----------+
| count(id) |
+-----------+
|   3287480 |
+-----------+
1 row in set (0.92 sec)

3.3.3.测试COUNT(*)
--------------
explain extended select count(*) from macrodb.test3
--------------

+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
|  1 | SIMPLE      | test3 | ALL  | NULL          | NULL | NULL    | NULL | 3285169 |   100.00 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------+-------+
1 row in set, 1 warning (0.00 sec)

--------------
show warnings
--------------

+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select count(0) AS `count(*)` from `macrodb`.`test3` |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

--------------
select count(*) from  macrodb.test3
--------------

+----------+
| count(*) |
+----------+
|  3287480 |
+----------+
1 row in set (0.85 sec)


结论:
1.除非要统计某列非空值的总数,否则任何情况一律用COUNT(*),效率比COUNT(列名)高很多
2.除非有特殊需要,否则COUNT(*)不要加WHERE条件,会严重影响效率,如果加了条件COUNT(*)和COUNT(主键)效率是一致的,COUNT(非主键)效率很低
3.在没有WHERE条件的情况下:COUNT(*)等于COUNT(主键)优于COUNT(非主键有索引)优于COUNT(非主键无索引)
4.只要加了WHERE就会降低效率,即使是WHERE 1=1
5.COUNT(*)MySQL会转为COUNT(1),COUNT(id)会计算NOT NULL值。
6.COUNT(1)和COUNT(0)一样。都是返回包括NULL在内的值。

你可能感兴趣的:(count(*),count(1),count(col),count(id))