• MySQL的count(*)执行慢的解决方案和不同count的比较


    业务中经常需要获取一个表的行数,但随着数据表不断增大,你会发现一条count(*)语句执行的效率越来越让人难以忍受。

    聊到这里,有必要介绍一下count的实现方式

    • 在MyISAM中,MyISAM直接记录了表的行数,执行count(*)会直接返回这个数字,因此效率很高。
    • 在InnoDB中,它会先把数据逐行读取出来,再累计计数,执行效率受数据量的影响。

    那么为什么InnoDB不能向MyISAM一样维护一个表行数呢?
    主要的原因是InnoDB所支持事务的多版本并发控制(MVCC),即使同一时刻执行同一语句也可能返回不同结果,维护一个count并没有什么意义。此外查询语句如果包含Where,那么即使MyISAM引擎也是需要花时间查找计数的。

    那么如何解决count语句的效率问题就变成了一个实际问题,解决这个问题的核心是使用缓存来减少执行查询语句,对于不同类型的数据我通常会使用下面几种不同的解决方案:

    1.实时性不是那么高的数据

    对于不需要实时获取准确的数据,一个很自然的想法就是缓存+有效期。程序第一次获取行数的时候先从缓存里面找,如果找不到再去执行count语句,然后把结果写入带有生命周期的缓存中。这个方案可以有效的规避count效率慢的问题,对于不同实效性要求的数据也可以很容易的设置不同的缓存周期,但面对要求实时准确的数据就无能为力了。

    2.要求实时准确的行数

    这一类数据的解决思路是,对数据表进行增删操作时,同步对缓存进行操作,这样就可以确保缓存中的行数永远都是最新的。
    这个解决方案也存其他在问题,比如我们使用redis缓存,如果某一时刻redis异常重启,如果在这个过程中数据表有新增数据,那么redis中的缓存数就会与实际行数存在差异,当然可以在启动redis时重新执行count语句来同步准确数字。
    即使redis不是异常重启,redis缓存的行数也可能与数据库中的不对。设想用户一个查询行数的请求恰好在MySQL新增数据和redis缓存+1的中间,这时候用户获取的行数就会比真实的数据量少1。

    3.绝对准确一致的数据

    上面说了第2种解决方案其实也不是绝对准确的,那么对于要求绝对准确的数据该怎么处理?思路其实还是和缓存一样,我们可以用MySQL单独建一张表来维护count,相比于缓存,这种解决方案可以充分利用MySQL的事务,可以确保对于任意时刻count和真实数量保持一致,用户每次查询数量时访问这张计数表即可。

    再来聊聊count(*), count(id), count(1)的性能区别
    对于count(*),优化器专门优化count(*)的语义为“取行数”,其他“显而易见”的优化并没有做

    对于count(主键id)来说,InnoDB引擎会遍历整张表,把每一行的id值都取出来,返回给server层。server层拿到id后,判断是不可能为空的,就按行累加。

    对于count(1)来说,InnoDB引擎遍历整张表,但不取值。server层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。

    单看这两个用法的差别的话,你能对比出来,count(1)执行得要比count(主键id)快。因为从引擎返回id会涉及到解析数据行,以及拷贝字段值的操作。

    对于count(字段)来说:

    • 如果这个“字段”是定义为not null的话,一行行地从记录里面读出这个字段,判断不能为null,按行累加;
    • 如果这个“字段”定义允许为null,那么执行的时候,判断到有可能是null,还要把值取出来再判断一下,不是null才累加。

    按照效率排序的话,count(字段)<count(主键id)<count(1)≈count(*),因此尽量使用count(*)。

  • 相关阅读:
    RealView MDK在链接时提示空间不够的解决方案总结
    不同的LCD之间程序移植时配置参考
    S3c2440ALCD控制器配置实例
    mini2440裸机之PWM
    对增益大于等于10时保持稳定的放大器进行补偿以在较低增益下工作
    ASP.NET HttpContext的时间戳属性
    C#验证邮箱,电话,手机,数字,英文,日期,身份证,邮编,网址,IP类.. (转)
    sqlhelper 实现回滚事务
    JQuery全选和反选
    js 获取前天、昨天、今天、明天、后天的时间 (转)
  • 原文地址:https://www.cnblogs.com/lazyfish007/p/13300890.html
Copyright © 2020-2023  润新知