mysql select count 与 select count 两个执行效率怎样

2024-11-26 23:28:15
推荐回答(3个)
回答1:

优化总结:
1.任何情况下select COUNT(*) from xxx 是最优选择;
2.尽量减少select COUNT(*) from xxx where col = ‘xxx’ 这种查询;
3.杜绝select COUNT(col) from tablename where col = ‘xxx’ 的出现。(其中col非主键)

环境:
MySQL版本:5.0.45
OS:Windows XP SP3
数据表一:sphinx
+———-+——————+——+—–+———+—————-+
| Field | Type | Null | key | Default | Extra |
+———-+——————+——+—–+———+—————-+
| id | int(10) unsigned | no | pri | NULL | auto_increment |
| til | varchar(100) | no | | | |
| content | text | no | | | |
| dataline | int(11) | no | | | |
+———-+——————+——+—–+———+—————-+
记录数:1120100
查询一:
mysql> select count(*) as totalnum from sphinx;
+———-+
| totalnum |
+———-+
| 1120100 |
+———-+
1 row in set (0.00 sec)
查询二:
mysql> select count(*) as totalnum from sphinx where id>1000;
+———-+
| totalnum |
+———-+
| 1119100 |
+———-+
1 row in set (2.17 sec)
查询三:
mysql> select count(*) as totalnum from sphinx where id>1000;
+———-+
| totalnum |
+———-+
| 1119100 |
+———-+
1 row in set (0.61 sec)
查询四:
mysql> select count(*) as totalnum from sphinx where id>1000;
+———-+
| totalnum |
+———-+
| 1119100 |
+———-+
1 row in set (0.61 sec)
查询五:
mysql> select count(id) as totalnum from sphinx;
+———-+
| totalnum |
+———-+
| 1120100 |
+———-+
1 row in set (0.00 sec)
查询六:
mysql> select count(til) as totalnum from sphinx where id>1000;
+———-+
| totalnum |
+———-+
| 1119100 |
+———-+
1 row in set (1 min 38.61 sec)
查询七:
mysql> select count(id) as totalnum from sphinx where id>11000;
+———-+
| totalnum |
+———-+
| 1109100 |
+———-+
1 row in set (0.61 sec)
查询八:
mysql> select count(id) as totalnum from sphinx;
+———-+
| totalnum |
+———-+
| 1120100 |
+———-+
1 row in set (0.03 sec)

结论:
在 select count() 没有 where 条件的时候 select count(*) 和 select count(col) 所消耗的查询时间相差无几。
在 select count() 有 where 条件的时候 select count(col) 所消耗的查询时间 比 select count(*) 明显多出数量级的时间。

回答2:

select count的要高一些。

回答3:

我们知道,MySQL 一直依赖对 count(*) 的执行很头疼。很早的时候,MyISAM 引擎自带计数器,可以秒回;不过 InnoDB 就需要实时计算,所以很头疼。以前有多方法可以变相解决此类问题,比如:
1. 模拟 MyISAM 的计数器比如表 ytt1,要获得总数,我们建立两个触发器分别对 insert/delete 来做记录到表 ytt1_count,这样只需要查询表 ytt1_count 就能拿到总数。ytt1_count 这张表足够小,可以长期固化到内存里。不过缺点就是有多余的触发器针对 ytt1 的每行操作,写性能降低。这里需要权衡。


2. 用 MySQL 自带的 sql_calc_found_rows 特性来隐式计算

依然是表 ytt1,不过每次查询的时候用 sql_calc_found_rows 和 found_rows() 来获取总数,比如:

  • 1 row in set, 1 warning (0.00 sec)

  • 这样的好处是写法简单,用的是 MySQL 自己的语法。缺点也有,大概有两点:1. sql_calc_found_rows 是全表扫。2. found_rows() 函数是语句级别的存储,有很大的不确定性,所以在 MySQL 主从架构里,语句级别的行级格式下,从机数据可能会不准确。不过行记录格式改为 ROW 就 OK。所以最大的缺点还是第一点。

  • 从 warnings 信息看,这种是 MySQL 8.0 之后要淘汰的语法。

    3. 从数据字典里面拿出来粗略的值


    那这样的适合新闻展示,比如行数非常多,每页显示几行,一般后面的很多大家也都不怎么去看。缺点是数据不是精确值。

    4. 根据表结构特性特殊的取值

  • 这里假设表 ytt1 的主键是连续的,并且没有间隙,那么可以直接  mysql> select max(id) as cnt from ytt1;    +------+    | cnt  |    +------+    | 3072 |    +------+    1 row in set (0.00 sec)


  • 不过这种对表的数据要求比较高。


    5. 标准推荐取法(MySQL 8.0.17 建议)

  • MySQL 8.0 建议用常规的写法来实现。

  • 第五种写法是 MySQL 8.0.17 推荐的,也就是说以后大部分场景直接实时计算就 OK 了。MySQL 8.0.17 以及在未来的版本都取消了sql_calc_found_rows 特性,可以查看第二种方法里的 warnings 信息。相比 MySQL 5.7,8.0 对 count(*) 做了优化,没有必要在用第二种写法了。我们来看看 8.0 比 5.7 在此类查询是否真的有优化?MySQL 5.7

  • 请点击输入图片描述