使用mysql的innodb引擎执行count查询时发现速度很慢。一个将近800万条数据的表执行count(*)差不多40多秒时间。使用count(1)和count(主键)也基本差不多。
表结构如下:

  • 执行count(*)
    1
    
    SELECT COUNT(*) FROM sds_third_match_info;
    

耗时:57.733sec

  • 执行count(1)
    1
    
    SELECT COUNT(1) FROM sds_third_match_info;
    

耗时:55.428sec

  • 执行count(主键)
    1
    
    SELECT COUNT(id) FROM sds_third_match_info;
    

耗时:56.209sec

原因分析:
InnoDB的索引是B+Tree。
对主键索引来说:它只有在叶子节点上存储数据,它的key是主键,并且value为整条数据。
对辅助索引来说:key为建索引的列,value为主键。

这给我们两个信息:

  1. 根据主键会查到整条数据
  2. 根据辅助索引只能查到主键,然后必须通过主键再查到剩余信息。

所以如果要优化count(*)操作的话,我们需要找一个短小的列,为它建立辅助索引。

我们在sport_data_type上建立一个普通索引

1
ALTER TABLE sds_third_match_info ADD INDEX idx_sporttype_stmi(sport_data_type);

然后根据索引列做count

1
SELECT COUNT(sport_data_type) FROM sds_third_match_info t;

现在耗时:2.649sec

如果在where条件中根据索引列过滤:

1
SELECT COUNT(sport_data_type) FROM sds_third_match_info t WHERE sport_data_type=1;

耗时:0.052sec

看看执行计划:
EXPLAIN SELECT COUNT(sport_data_type) FROM sds_third_match_info t WHERE sport_data_type=1;

如果是count(*)则执行计划是全表扫描。

参考:高性能MySQL之Count统计查询MySQL 大表的count()优化