读书人

[真伪]数据库中 select count(1) 比 s

发布时间: 2012-03-25 20:55:16 作者: rapoo

[真伪]数据库中 select count(1) 比 select count(*) 快?
论坛上经常看到一种观点,就是 select count(1) from table1 .. 比 select count(*) from table1 .. 要快。

看看大家什么观点,
估计大家都知道 select 1 from table1 肯定比 select * from table1 要快。但这个count(1) 与 count(*) 对比是如何呢?

发个贴子大家讨论讨论。

A) count(1) 快于 count(*)
B) count(1) 慢于 count(*)
C) count(1) 速度上等同于 count(*)
D) 说不准,count(1) count(*) 哪个快不一定。

[解决办法]
明天去公司测试一下
[解决办法]
较高版本的数据库,c)
[解决办法]
count(1) 指的是 count(第1列) 吧,而 count(*) 自己选择主键列统计。

count(1) 比 count(*) 是没有依据的,或许是因为有些人自认为的优化措施罢了!

SELECT * 与 COUNT(*) 这里的“*”完全是不同的意义!认为 COUNT(1) 比 COUNT(*) 快的人,肯定没有理解 SELECT * 与 COUNT(*) 中“*”表示的意义是不一样的!
[解决办法]

探讨

count(1) 指的是 count(第1列) 吧,而 count(*) 自己选择主键列统计。

[解决办法]
其实我一直想去看看数据库内部的实现 前提是等我有深厚的功底时

到时候这些问题就都知道了
[解决办法]
公司不让用*,不知为什么,我也没弄懂,持续关注中!
[解决办法]
count(主键)肯定是最优的方法之一,至于count(*),count(1)在oracle中有可能和count(pk)一样,可能比它慢,但是不能看比它快


其他数据库我不熟悉
[解决办法]
路过,看一看
[解决办法]
来学习的
[解决办法]
没什么意义吧 不同得数据库有不同优化方法 如果有where条件得话则应该一样了
[解决办法]
C。。。。
[解决办法]
这个在公司好像讨论过这个问题,貌似select count(*)快一些。
[解决办法]
这个我认为是差不多,当然没有测试也没有根据。所以我每次是看心情来用,有时1有时*
[解决办法]
count(1),其实就是计算一共有多少符合条件的行。
1并不是表示第一个字段,而是表示一个固定值。
其实就可以想成表中有这么一个字段,这个字段就是固定值1,count(1),就是计算一共有多少个1.
同理,count(2),也可以,得到的值完全一样,count('x'),count('y')都是可以的。一样的理解方式。在你这个语句理都可以使用,返回的值完全是一样的。就是计数。
count(*),执行时会把星号翻译成字段的具体名字,效果也是一样的,不过多了一个翻译的动作,比固定值的方式效率稍微低一些。
百度知道里面看到的一个人的回答,希望对楼主有用
[解决办法]
[code=SQL]mysql> use astar
Database changed
mysql> select count(*) from trans;
+----------+
| count(*) |
+----------+
| 542535 |
+----------+
1 row in set (0.41 sec)

mysql> Select count(1) from trans;
+----------+
| count(1) |
+----------+
| 542535 |
+----------+
1 row in set (0.20 sec)

mysql> Select count(*) from transdetail;
+----------+
| count(*) |
+----------+
| 906699 |
+----------+
1 row in set (0.28 sec)

mysql> select count(1) from transdetail;
+----------+
| count(1) |
+----------+
| 906699 |
+----------+
1 row in set (0.30 sec)

mysql> select count(*) from transpayment;
+----------+
| count(*) |
+----------+
| 542505 |
+----------+
1 row in set (0.33 sec)

mysql> Select count(1) from transpayment;
+----------+
| count(1) |
+----------+
| 542505 |
+----------+
1 row in set (0.20 sec)



mysql> USE C1
Database changed
mysql> select count(*) from trans;
+----------+
| count(*) |
+----------+
| 135 |
+----------+
1 row in set (0.17 sec)

mysql> select count(1) from trans;
+----------+
| count(1) |
+----------+
| 135 |
+----------+
1 row in set (0.00 sec)
code]
个人测试结果:数据少的时候,用COUNT(*)会比COUNT(1)快,
当数据量比较大的时候,COUNT(1)就快过COUNT(*)


[解决办法]
B
[解决办法]
以后用mssql测试过
在网上还有人说count(9)比其它的都快 bug!!
我测试的结果在当时那个条件是运行了n次都是count(1)最快。
不过差别太小,如果环境不一样可能结果不一样!

[解决办法]
同意下面的说法:

[code=SQL]mysql> use astar
Database changed
mysql> select count(*) from trans;
+----------+
| count(*) |
+----------+
| 542535 |
+----------+
1 row in set (0.41 sec)

mysql> Select count(1) from trans;
+----------+
| count(1) |
+----------+
| 542535 |
+----------+
1 row in set (0.20 sec)

mysql> Select count(*) from transdetail;
+----------+
| count(*) |
+----------+
| 906699 |
+----------+
1 row in set (0.28 sec)

mysql> select count(1) from transdetail;
+----------+
| count(1) |
+----------+
| 906699 |
+----------+
1 row in set (0.30 sec)

mysql> select count(*) from transpayment;
+----------+
| count(*) |
+----------+
| 542505 |
+----------+
1 row in set (0.33 sec)

mysql> Select count(1) from transpayment;
+----------+
| count(1) |
+----------+
| 542505 |
+----------+
1 row in set (0.20 sec)

mysql> USE C1
Database changed
mysql> select count(*) from trans;
+----------+
| count(*) |
+----------+
| 135 |
+----------+
1 row in set (0.17 sec)

mysql> select count(1) from trans;
+----------+
| count(1) |
+----------+
| 135 |
+----------+
1 row in set (0.00 sec)
code]
个人测试结果:数据少的时候,用COUNT(*)会比COUNT(1)快,
当数据量比较大的时候,COUNT(1)就快过COUNT(*)

[解决办法]
我认为基本差不多吧,o(∩_∩)o...
[解决办法]
汗~~上面说反了,
个人测试结果:数据少的时候,用COUNT(1)会比COUNT(*)快,
当数据量比较大的时候,COUNT(*)就快过COUNT(1)。
可能也有表设计有关系有吧,单个PRIMARY和联合PRIMARY可能执行效果也都不一样吧。
[解决办法]
select count(1) 百分百快 但是这需要你添加几百万数据后才会更明显
[解决办法]

SQL code
-- 执行计划一样,所以:应该是差不多,不过我们习惯不用*,而用常数(1)!mysql> explain select count(*) from t_Groupon_order\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: t_Groupon_order         type: indexpossible_keys: NULL          key: ONLINE_ID_KEY      key_len: 9          ref: NULL         rows: 7788848        Extra: Using index1 row in set (0.00 sec)mysql> explain select count(1) from t_Groupon_order\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: t_Groupon_order         type: indexpossible_keys: NULL          key: ONLINE_ID_KEY      key_len: 9          ref: NULL         rows: 7788882        Extra: Using index1 row in set (0.00 sec)
[解决办法]
这个只能说跟数据库的实现有关系。
在过去低版本的实现当中,count(1)可能要快于count(*), 但是高版本的实现里头,两者可能完全一样。




[解决办法]
这要看DBMS如何处理了,

MSSql是这样定义的:
COUNT(*):返回记录总数,不会读取行上的任何信息,
COUNT(1):返回记录总数,但是会在每一行读取1

MySql,只要不是读取行的所有列,还是优先使用COUNT(*)
[解决办法]
由于数据库引擎的不同结果也会不一样,所以测试了 MyISAM 和 InnoDB 两种引擎,后面是测试过程的输出,结论如下:
1. InnoDB 对于各种形式的 count 均一样,需要全表扫描进行计算,对于非主键的列进行计算结果反而更快(可能是缓存的影响?)
2. MyISAM 对于非主键的列进行 count 会慢一些,其它的形式均很快。对于 count(*) 肯定是直接读取数据库的“行数”属性,其它的也是 0 秒的形式不大清楚其实际计算过程
3. 对于不同的数据库系统和不同的引擎可能实现上不同,所以此题目所说的比较需要基于不同的环境进行

------------------------------------------------

------------------------------------------------

测试过程:

SQL code
Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 31 to server version: 5.1.6-alpha-nt-maxType 'help;' or '\h' for help. Type '\c' to clear the buffer.mysql> use test;Database changedmysql>mysql> drop table if exists tb_myisam;Query OK, 0 rows affected (0.01 sec)mysql> CREATE TABLE tb_myisam (    ->   id int(10) NOT NULL auto_increment,    ->   name char(10) default NULL,    ->   PRIMARY KEY  (id)    -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;Query OK, 0 rows affected (0.05 sec)mysql>mysql> drop table if exists tb_innodb;Query OK, 0 rows affected (0.05 sec)mysql> CREATE TABLE tb_innodb (    ->   id int(10) NOT NULL auto_increment,    ->   name char(10) default NULL,    ->   PRIMARY KEY  (id)    -> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;Query OK, 0 rows affected (0.08 sec)mysql>mysql> drop procedure if exists testdata;Query OK, 0 rows affected (0.00 sec)mysql> delimiter $$mysql> create procedure testdata()    -> begin    -> declare i int;    -> set i = 0;    -> while i <5000000    -> do    -> insert into tb_myisam(name) values(ceil(rand()*100));    -> set i = i + 1;    -> end while;    -> end;    -> $$Query OK, 0 rows affected (0.00 sec)mysql> delimiter ;mysql>mysql> call testdata();Query OK, 1 row affected (4 min 6.86 sec)mysql>mysql> insert into tb_innodb    -> select * from tb_myisam;Query OK, 5000000 rows affected (1 min 31.47 sec)Records: 5000000  Duplicates: 0  Warnings: 0mysql>mysql> select count(1) from tb_innodb;+----------+| count(1) |+----------+|  5000000 |+----------+1 row in set (7.75 sec)mysql> select count(id) from tb_innodb;+-----------+| count(id) |+-----------+|   5000000 |+-----------+1 row in set (7.17 sec)mysql> select count(name) from tb_innodb;+-------------+| count(name) |+-------------+|     5000000 |+-------------+1 row in set (6.22 sec)mysql> select count(*) from tb_innodb;+----------+| count(*) |+----------+|  5000000 |+----------+1 row in set (6.34 sec)mysql>mysql> select count(1) from tb_myisam;+----------+| count(1) |+----------+|  5000000 |+----------+1 row in set (0.00 sec)mysql> select count(id) from tb_myisam;+-----------+| count(id) |+-----------+|   5000000 |+-----------+1 row in set (0.00 sec)mysql> select count(name) from tb_myisam;+-------------+| count(name) |+-------------+|     5000000 |+-------------+1 row in set (1.24 sec)mysql> select count(*) from tb_myisam;+----------+| count(*) |+----------+|  5000000 |+----------+1 row in set (0.00 sec)mysql>mysql> truncate table tb_innodb;Query OK, 5000284 rows affected (0.08 sec)mysql> truncate table tb_myisam;Query OK, 0 rows affected (0.02 sec)mysql>
[解决办法]
一个表 a 有 b,c,d,e,f 五个字段。两种方式进行查询。
SQL code
①select * from a②select b,c,d,e,ffrom a两者的执行速度。当有大量记录的时候②的速度明显的快于①当记录很少的时候①的速度快于②因为查找的时候 都是从系统表里面在查找,a表的内容都是存在系统表里面的。select * 会查询所有的系统表当选择条件后,查找的系统表的数目会减少。 


[解决办法]
一般情况下,两着返回结果是一样的

假如表有主键(Primary key), 那么count(1)比count(*)快

如果有主键的,那主键作为count的条件时候count(主键)最快

如果你的表只有一个字段的话那count(*)就是最快的

count(*) 跟 count(1) 的结果一样,都包括对NULL的统计
count(column) 是不包括NULL的统计

[解决办法]
INNODB,MYSQL5.1.32,,10万条记录测试
SELECT SQL_NO_CACHE COUNT(XM) FROM JZG1;0.097
SELECT SQL_NO_CACHE COUNT(1) FROM JZG1;0.058
SELECT SQL_NO_CACHE COUNT(*) FROM JZG1;0.071
SELECT SQL_NO_CACHE COUNT(BH) FROM JZG1;0.085
在XM上建立有复合索引,BH上单独索引

myisam,MYSQL5.1.32,,10万条记录测试
在XM上建立有复合索引,BH上单独索引
SELECT SQL_NO_CACHE COUNT(XM) FROM JZG1;0.042
SELECT SQL_NO_CACHE COUNT(1) FROM JZG1;0.000
SELECT SQL_NO_CACHE COUNT(*) FROM JZG1;0.000
SELECT SQL_NO_CACHE COUNT(BH) FROM JZG1;0.036

在MYISAM引擎下,两者速度一致
在INNODB引擎下,COUNT(1)略快于COUNT(*)
[解决办法]
上百万数据。引擎不同。确实不同。


INNODB **********************************

Array ( [count(*)] => 1138446 ) 2.555640
-----------------------
Array ( [count(*)] => 1139702 ) 2.20650
-----------------------
Array ( [count(1)] => 1138446 ) 2.591530
-----------------------
Array ( [count(1)] => 1139702 ) 2.056590



MYISAM **********************************
Array ( [count(*)] => 1138446 ) 0.622220
-----------------------
Array ( [count(*)] => 1139702 ) 0.000270
-----------------------
Array ( [count(1)] => 1138446 ) 0.568510
-----------------------
Array ( [count(1)] => 1139702 ) 0.000380
[解决办法]
MYISAM下,COUNT(*)直接去系统表里取出这个表的总行数这个字段的值返回就完了。相当于从一个几百行的表里查。

SQL code
mysql> select table_rows from information_schema.tables where table_name='t1';+------------+| table_rows |+------------+|          4 |+------------+1 row in set (0.00 sec)
[解决办法]
末学测试结果是一样的

可以用explain extended加上show warnings得到数据执行计划,执行结果如下

SQL code
mysql> select version();+----------------------+| version()            |+----------------------+| 5.1.57-community-log |+----------------------+1 row in set (0.01 sec)CREATE TABLE `tablets_history` (  `tablet_id` varchar(32) NOT NULL DEFAULT '0',  `activity_id` varchar(32) NOT NULL DEFAULT '',  `user_id` varchar(32) NOT NULL DEFAULT '0',  `tablet_type` tinyint(3) NOT NULL DEFAULT '0',  `memory` varchar(255) NOT NULL DEFAULT '',  `presenter_name` varchar(255) NOT NULL DEFAULT '',  `confirmed` tinyint(3) NOT NULL DEFAULT '0',  `deleted` tinyint(3) NOT NULL DEFAULT '0',  `concurrency_mark` tinyint(3) NOT NULL DEFAULT '1',  `printed` tinyint(3) NOT NULL DEFAULT '0',  `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  `rejected_comments` varchar(500) DEFAULT '',  `import_tablet_id` varchar(32) NOT NULL DEFAULT '',  PRIMARY KEY (`tablet_id`),  KEY `activity_id` (`activity_id`),  KEY `user_id` (`user_id`,`tablet_type`,`deleted`,`confirmed`,`concurrency_mark`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `tablets_history_myisam` (  `tablet_id` varchar(32) NOT NULL DEFAULT '0',  `activity_id` varchar(32) NOT NULL DEFAULT '',  `user_id` varchar(32) NOT NULL DEFAULT '0',  `tablet_type` tinyint(3) NOT NULL DEFAULT '0',  `memory` varchar(255) NOT NULL DEFAULT '',  `presenter_name` varchar(255) NOT NULL DEFAULT '',  `confirmed` tinyint(3) NOT NULL DEFAULT '0',  `deleted` tinyint(3) NOT NULL DEFAULT '0',  `concurrency_mark` tinyint(3) NOT NULL DEFAULT '1',  `printed` tinyint(3) NOT NULL DEFAULT '0',  `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  `rejected_comments` varchar(500) DEFAULT '',  `import_tablet_id` varchar(32) NOT NULL DEFAULT '',  PRIMARY KEY (`tablet_id`),  KEY `activity_id` (`activity_id`),  KEY `user_id` (`user_id`,`tablet_type`,`deleted`,`confirmed`,`concurrency_mark`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;mysql> select count(*) from tablets_history;+----------+| count(*) |+----------+|   485406 |+----------+1 row in set (0.12 sec)mysql> explain extended select count(*) from tablets_history;+----+-------------+-----------------+-------+---------------+-------------+---------+------+--------+----------+-------------+| id | select_type | table           | type  | possible_keys | key         | key_len | ref  | rows   | filtered | Extra       |+----+-------------+-----------------+-------+---------------+-------------+---------+------+--------+----------+-------------+|  1 | SIMPLE      | tablets_history | index | NULL          | activity_id | 98      | NULL | 485071 |   100.00 | Using index |+----+-------------+-----------------+-------+---------------+-------------+---------+------+--------+----------+-------------+1 row in set, 1 warning (0.00 sec)mysql> show warnings;+-------+------+---------------------------+| Level | Code | Message                                                       |+-------+------+---------------------------+| Note  | 1003 | select count(0) AS `count(*)` from `paiwei`.`tablets_history` |+-------+------+---------------------------+1 row in set (0.00 sec)mysql> explain extended select count(1) from tablets_history;+----+-------------+-----------------+-------+---------------+-------------+---------+------+--------+----------+-------------+| id | select_type | table           | type  | possible_keys | key         | key_len | ref  | rows   | filtered | Extra       |+----+-------------+-----------------+-------+---------------+-------------+---------+------+--------+----------+-------------+|  1 | SIMPLE      | tablets_history | index | NULL          | activity_id | 98      | NULL | 485071 |   100.00 | Using index |+----+-------------+-----------------+-------+---------------+-------------+---------+------+--------+----------+-------------+1 row in set, 1 warning (0.00 sec)mysql> show warnings;+-------+------+---------------------------+| Level | Code | Message                                                       |+-------+------+---------------------------+| Note  | 1003 | select count(1) AS `count(1)` from `paiwei`.`tablets_history` |+-------+------+---------------------------+1 row in set (0.00 sec)mysql> select count(*) from tablets_history_myisam;+----------+| count(*) |+----------+|   485406 |+----------+1 row in set (0.00 sec)mysql> explain extended select count(*) from tablets_history_myisam;+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                        |+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Select tables optimized away |+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+1 row in set, 1 warning (0.00 sec)mysql> show warnings;+-------+------+----------------------------------+| Level | Code | Message                                                              |+-------+------+----------------------------------+| Note  | 1003 | select count(0) AS `count(*)` from `paiwei`.`tablets_history_myisam` |+-------+------+----------------------------------+1 row in set (0.00 sec)mysql> explain extended select count(1) from tablets_history_myisam;+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                        |+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Select tables optimized away |+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+1 row in set, 1 warning (0.00 sec)mysql> show warnings;+-------+------+----------------------------------+| Level | Code | Message                                                              |+-------+------+----------------------------------+| Note  | 1003 | select count(1) AS `count(1)` from `paiwei`.`tablets_history_myisam` |+-------+------+----------------------------------+1 row in set (0.00 sec) 


[解决办法]
A) count(1) 快于 count(*)
同意这点,
不过没什么实际意义,只要不select * 就好,
接分。
[解决办法]
count(1) 是绝对快,它只统计记录条数,对条件下的表扫描一遍而已
count(*) 是可能快,有主键的时候只扫主键,主键数等于记录数
count(主键)=count(1)
[解决办法]
1200W记录下,MYISAM,count(*)=count(1)
[解决办法]

探讨

[code=SQL]mysql> use astar
Database changed
mysql> select count(*) from trans;
+----------+
| count(*) |
+----------+
| 542535 |
+----------+
1 row in set (0.41 sec)

mysql> Select count(……

[解决办法]
一般情况下,两着返回结果是一样的

假如表有主键(Primary key), 那么count(1)比count(*)快

如果有主键的,那主键作为count的条件时候count(主键)最快

如果你的表只有一个字段的话那count(*)就是最快的

count(*) 跟 count(1) 的结果一样,都包括对NULL的统计
count(column) 是不包括NULL的统计
[解决办法]
COUNT(*) 和 COUNT(1)....性能是一样的,只是一个写法容易读懂,更具有可读性,另外一个优点像偏方...


#*********************#
技术网站:www.mysqlops.com
新浪微博:http://weibo.com/mysqlops
#*********************#

读书人网 >Mysql

热点推荐