数据库
COUNT查询优化
  • 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等缓存系统