• Mysql 系列 | count(*)


    项目中常常需要统计表数据总数,select count(*) from t;

    在 InnoDB 搜索引擎中,count(*) 需要把数据都读到内存中然后计数,数据很多时会很慢。

    count 字段或者 ID,会不会好一些呢!实际上在 Mysql 中,count(字段) < count(主键id) < count(1) ≈ count(*),也就是说 count(*) 是最佳方案。

    除此之外,可以考虑把计数保存起来,缓存或者数据库。

    count(*) 的实现方式

    • MyISAM 中,会把表的总行数存在磁盘中,可以直接读出来,效率很高。

    • InnoDB 中,有多版本并发控制(MVCC),可重复读时默认隔离级别。每个事务中读取的行数不一定相同,所以每次查询的时候,需要一行一行读取依次判断可见性,并计数。

    • InnoDB 中,count(*) 已经被优化过。优化器会选择最小的索引树遍历,在保证逻辑正确的情况下,尽量减少数据的扫描行数。

    • show table status 命令取到的 table_rows 是采样估算的结果,误差可能达到 40% - 50%,不能直接使用。

    缓存系统保存计数

    • 把计数存在 Redis 中,表中每添加一条数据,更新一次 Redis 的值

    • 数据库中表数据插入过程中,Redis 异常重启,会导致数据丢失。不过可以在重启后,去表中 count 得到正确的数值更新到 Redis 中。

    • Redis 正常工作时,因为 InnoDB 的 MVCC 机制,每个事务应该读到的总行数是不同的。而从 Redis 中则只能读到最新统计的行数,也是不精确的

    数据库保存计数

    • 表中新增数据时,更新计数表中的数据

    • 因为实在同一存储系统,可以保证逻辑一致性。不过每次需要从表中查得计数值。

    不同 count 的用法

    count() 是个聚合函数。对于返回的结果集,判断参数不为 NULL 时统计值加一,否则不加。最终返回统计结果。

    count(主键 ID)

    • InnoDB 会遍历整张表,取出 ID 返回给 Server 层,判断是不可能为空的,然后按行累加。

    count(1)

    • 遍历整张表,但不取数据。Server 层对于返回的每一行数据,放一个数字 1,判断不可能为空,逐行累加。

    • 相比 count(ID) 更快。没有取数据的步骤,减少了从引擎返回 ID 后解析数据,拷贝字段值的操作。

    count(字段)

    • 字段定义为 not null,从记录中读出字段,判断不能为空,逐行累加。

    • 字段定义为null,要把字段取出来,判断不为空,才会累加。

    count(*)

    • 已经被优化过,不会取值,肯定不为空,逐行累加。
  • 相关阅读:
    [BZOJ2738]矩阵乘法
    [BZOJ2084][Poi2010]Antisymmetry
    [BZOJ2095][Poi2010]Bridges
    [BZOJ1294][SCOI2009]围豆豆Bean
    [AtCoderContest075F]Mirrored
    [AtCoderContest015D]A or...or B Problem
    [UOJ#276]【清华集训2016】汽水
    忠诚的皇家守卫团——中间件
    Django(五):视图和路由系统
    Django(四):ORM
  • 原文地址:https://www.cnblogs.com/rendd/p/16572483.html
Copyright © 2020-2023  润新知