- By刘立博
- 2020-03-08 19:27:01
- 846人已阅读
COUNT()的作用
COUNT()是一个特殊的函数,有两个作用:
(1)统计某个列,满足列表达式的数量
如果在COUNT()中指定了列或列的表达式,则统计该列或满足列表达式有值的结果数,此处的有值指的是非NULL。如:
假定数据表use_count数据如下:
COUNT只统计值非NULL
统计条件互斥的两列
利用COUNT()不统计NULL的特性,可以在列表达式书写出普通WHERE条件实现较为复杂的约束条件。如:统计出cid=3或者name=1的函数
(2)统计结果集行数
如使用COUNT(*)的时候,MYSQL并不会统计结果集列的的行数,而是直接返回结果集的行数。
MYISAM对COUNT的优化
MYISAM存储引擎额外记录了数据表的行数,所以当没有指定任何WHERE条件时,MYISAM存储引擎会直接返回数据表的行数,而无需进行查询。如果COUNT语句中包含了约束条件,MYISAM就和其他存储引擎一样了。
可见MYISAM没有扫描任何行,便返回了结果
使用了WHERE条件后MYISAM和INNODB表现一致
INNODB下的COUNT(*)与COUNT(列)
可见使用*进行COUNT时,INNODB将*优化为主键进行统计,而使用其他字段时(即便cid字段声明为NOT NULL),则不会进行优化
MYISAM下的COUNT(*)和COUNT(列)
对COUNT(非主键)的处理上,MYISAM由所不同,如果是一个非空列,MYISAM会直接返回数据表的行数;如果列可能存在NULL值时,MYISAM才会对实际的列进行统计
MYISAM使用COUNT(*)减少扫描行数
可以利用COUNT(*)不扫描表的特性,加速一些特定的统计语句。如如何快速查询出ID大于5的城市:
PS:此处使用MYSQL数据模板SAKILA中的city表进行测试:
当我们使用传统的city_id>5时,MYISAM存储引擎需要扫描595行
通过对数据表分析可知ID>5的数量远远大于ID<=5的数据,所以可以编写以下SQL减少扫描的行数
可见,只需扫描6行即可得出结果
使用EXPLAIN获取近似值
EXPLAIN可以生成MYSQL的执行计划,其中有一个很有趣的字段ROWS,他预估了MYSQL可能会扫描的行数;有时,我们可以利用ROWS获取COUNT语句的近似值:
实际使用COUNT进行验证
INNODB获取数据表总行数
MYISAM记录了数据表的总行数,INNODB也能享受这项福利吗?答案是肯定的。我们可以通过访问MYSQL内部表来实现此功能:
可以使用以下SQL:SELECT TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA='库名' AND TABLE_NAME='表名';
进一步优化
毋庸置疑COUNT()需要扫描大量的数据行才能获得精确的结果,在不使用其他技术优化的情况下,最好的情况就是覆盖索引了。如果这仍然不能满足需求,那么可以考虑计数表或者使用redis、memcached等缓存系统