count 订阅
英文词,理解为:古代的一种贵族称号;或者是一种电脑计算机内部的数学函数的名字。 展开全文
英文词,理解为:古代的一种贵族称号;或者是一种电脑计算机内部的数学函数的名字。
信息
作    用
一种电脑计算机内部的数学函数
语    法
COUNT(value1,value2, ...)
性    质
一种电脑计算机内部的数学函数
外文名
Count
Count定义
计算参数列表中的数字项的个数
收起全文
精华内容
下载资源
问答
  • MySQL中count是怎样执行的?———count(1),count(id),count(非索引列),count(二级索引列)的分析

    1. 前言

      相信在此之前,很多人都只是记忆,没去理解,只知道count(*)count(1)包括了所有行,在统计结果的时候,不会忽略列值为NULLcount(列名)只统计列名那一列,在统计结果的时候,会忽略列值为NULL的记录。

      下面就从原理上给大家分析一下。


    2. 建表

    和前面一样,用的同一个表,表中有将近10W条数据

    CREATE TABLE demo_info(
        id INT NOT NULL auto_increment,
        key1 VARCHAR(100),
        key2 INT,
        key3 VARCHAR(100),
        key_part1 VARCHAR(100),
        key_part2 VARCHAR(100),
        key_part3 VARCHAR(100),
        common_field VARCHAR(100),
        PRIMARY KEY (id),
        KEY idx_key1 (key1),
        UNIQUE KEY uk_key2 (key2),
        KEY  idx_key3 (key3),
        KEY idx_key_part(key_part1, key_part2, key_part3)
    )ENGINE = INNODB CHARSET=utf8mb4;
    

    3. count是怎么样执行的?

    经常会看到这样的例子:
    当你需要统计表中有多少数据的时候,会经常使用如下语句

    SELECT COUNT(*) FROM demo_info;
    

      由于聚集索引和非聚集索引中的记录是一一对应的,而非聚集索引记录中包含的列(索引列+主键id)是少于聚集索引(所有列)记录的,所以同样数量的非聚集索引记录比聚集索引记录占用更少的存储空间。如果我们使用非聚集索引执行上述查询,即统计一下非聚集索引uk_key2中共有多少条记录,是比直接统计聚集索引中的记录数节省很多I/O成本。所以优化器会决定使用非聚集索引uk_key2执行上述查询

    注意:这里已经验证过了,uk_key2比其他索引成本更低。 详情可见MySQL查询为什么选择使用这个索引?——基于MySQL 8.0.22索引成本计算

    分析一下执行计划

    在执行上述查询时,server层会维护一个名叫count的变量,然后:

    • server层向InnoDB要第一条记录。

    • InnoDB找到uk_key2的第一条二级索引记录,并返回给server层(注意:由于此时只是统计记录数量,所以并不需要回表)。

    • 由于count函数的参数是*MySQL会将*当作常数0处理。由于0并不是NULLserver层给count变量加1

    • server层向InnoDB要下一条记录。

    • InnoDB通过二级索引记录的next_record属性找到下一条二级索引记录,并返回给server层。

    • server层继续给count变量加1

    • 重复上述过程,直到InnoDBserver层返回没记录可查的消息。

    • server层将最终的count变量的值发送到客户端。


    4. count(1),count(id),count(非索引列),count(二级索引列)的分析

    来看看count(1)

    SELECT COUNT(1) FROM demo_info;
    

    执行计划和count(*)一样

      对于count(*)count(1)或者任意的count(常数)来说,读取哪个索引的记录其实并不重要,因为server层只关心存储引擎是否读到了记录,而并不需要从记录中提取指定的字段来判断是否为NULL。所以优化器会使用占用存储空间最小的那个索引来执行查询

    再看一下count(id)

    explain SELECT COUNT(id) FROM demo_info;
    

      对于count(id)来说,由于id是主键,不论是聚集索引记录,还是任意一个二级索引记录中都会包含主键字段,所以其实读取任意一个索引中的记录都可以获取到id字段,此时优化器也会选择占用存储空间最小的那个索引来执行查询

    再看一下count(非索引列)

    explain select count(common_field) from demo_info
    

      对于count(非索引列)来说,优化器选择全表扫描,说明只能在聚集索引的叶子结点顺序扫描。

    请确认你理解了全表扫描,它是顺序扫描聚集索引的所有叶子结点并判断。

      而对于其他二级索引列,count(二级索引列),优化器只能选择包含我们指定的列的索引去执行查询,只能去指定非聚集索引的B+树扫描 ,可能导致优化器选择的索引扫描代价并不是最小。

    综上所述:
      对于count(*)count(常数)count(主键)形式的count函数来说,优化器可以选择扫描成本最小的索引执行查询,从而提升效率,它们的执行过程是一样的,只不过在判断表达式是否为NULL时选择不同的判断方式,这个判断为NULL的过程的代价可以忽略不计,所以我们可以认为count(*)count(常数)count(主键)所需要的代价是相同的。

      而对于count(非索引列)来说,优化器选择全表扫描,说明只能在聚集索引的叶子结点顺序扫描。

      count(二级索引列)只能选择包含我们指定的列的索引去执行查询,可能导致优化器选择的索引执行的代价并不是最小。

      其实上述这些区别就是因为非聚集索引记录比聚集索引记录占用更少的存储空间,减少更多I/O成本,所以优化器才有了不同索引的选择,仅此而已。



    欢迎一键三连~

    有问题请留言,大家一起探讨学习

    ----------------------Talk is cheap, show me the code-----------------------
    展开全文
  • MySQL的COUNT语句--count(*)、 count(常量)、 count(列名)

    千次阅读 多人点赞 2019-10-21 10:22:20
    MySQL的COUNT语句–count(*)、 count(常量)、 count(列名) 数据库查询相信很多人都不陌生,所有经常有人调侃程序员就是CRUD专员,这所谓的CRUD指的就是数据库的增删改查。 在数据库的增删改查操作中,使用最频繁的...

    MySQL的COUNT语句–count(*)、 count(常量)、 count(列名)

    数据库查询相信很多人都不陌生,所有经常有人调侃程序员就是CRUD专员,这所谓的CRUD指的就是数据库的增删改查。

    在数据库的增删改查操作中,使用最频繁的就是查询操作。 而在所有查询操作中,统计数量操作更是经常被用到。

    关于数据库中行数统计,无论是MySQL还是Oracle,都有一个函数可以使用,那就是COUNT

    但是,就是这个常用的COUNT函数,却暗藏着很多玄机,尤其是在面试的时候,一不小心就会被虐。 不信的话请尝试回答下以下问题:

    1、COUNT有几种用法?

    2、COUNT(字段名)和COUNT(*)的查询结果有什么不同?

    3、COUNT(1)和COUNT(*)之间有什么不同?

    4、COUNT(1)和COUNT(*)之间的效率哪个更高?

    5、为什么《阿里巴巴Java开发手册》建议使用COUNT(*)

    6、MySQL的MyISAM引擎对COUNT(*)做了哪些优化?

    7、MySQL的InnoDB引擎对COUNT(*)做了哪些优化?

    8、上面提到的MySQL对COUNT(*)做的优化,有一个关键的前提是什么?

    9、SELECT COUNT(*) 的时候,加不加where条件有差别吗?

    10、COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的?

    以上10道题,如果您可以全部准确无误的回答的话,那说明你真的很了解COUNT函数了,如果有哪些知识点是不了解的,那么本文正好可以帮你答疑解惑。

    1、认识COUNT

    关于COUNT函数,在MySQL官网中有详细介绍:

    简单翻译一下:

    1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。 结果是一个BIGINT值。

    2、如果查询结果没有命中任何记录,则返回0

    3、但是,值得注意的是, COUNT(*) 的统计结果中,会包含值为NULL的行数。

    create table t_count(id int,id2 int);
    insert into t_count values(null,null);
    insert into t_count values(1,null);
    insert into t_count values(null,1);
    insert into t_count values(1,null);
    insert into t_count values(null,1);
    insert into t_count values(1,null);
    insert into t_count values(null,null);
    select count(*),count(id),count(id2),count(1) from t_count;
    

    即以下表记录

    root@localhost[lhrdb]> create table t_count(id int,id2 int);
    Query OK, 0 rows affected (0.36 sec)
    root@localhost[lhrdb]> insert into t_count values(null,null);
    Query OK, 1 row affected (0.07 sec)
    
    root@localhost[lhrdb]> insert into t_count values(1,null);
    Query OK, 1 row affected (0.06 sec)
    
    root@localhost[lhrdb]> insert into t_count values(null,1);
    Query OK, 1 row affected (0.08 sec)
    
    root@localhost[lhrdb]> insert into t_count values(1,null);
    Query OK, 1 row affected (0.03 sec)
    
    root@localhost[lhrdb]> insert into t_count values(null,1);
    Query OK, 1 row affected (0.05 sec)
    
    root@localhost[lhrdb]> insert into t_count values(1,null);
    Query OK, 1 row affected (0.03 sec)
    
    root@localhost[lhrdb]> insert into t_count values(null,null);
    Query OK, 1 row affected (0.08 sec)
    
    root@localhost[lhrdb]> 
    root@localhost[lhrdb]> select * from t_count;
    +------+------+
    | id   | id2  |
    +------+------+
    | NULL | NULL |
    |    1 | NULL |
    | NULL |    1 |
    |    1 | NULL |
    | NULL |    1 |
    |    1 | NULL |
    | NULL | NULL |
    +------+------+
    7 rows in set (0.00 sec)
    
    

    使用语句count(*),count(id),count(id2)查询结果如下:

    root@localhost[lhrdb]> select count(*),count(id),count(id2),count(1),count(2) from t_count;
    
    +----------+-----------+------------+----------+----------+
    | count(*) | count(id) | count(id2) | count(1) | count(2) |
    +----------+-----------+------------+----------+----------+
    |        7 |         3 |          2 |        7 |        7 |
    +----------+-----------+------------+----------+----------+
    
    1 row in set (0.00 sec)
    

    除了 COUNT(id) 和 COUNT() 以外,还可以使用 COUNT(常量) (如 COUNT(1) )来统计行数,那么这三条SQL语句有什么区别呢? 到底哪种效率更高呢? 为什么《阿里巴巴Java开发手册》中强制要求不让使用 COUNT(列名) 或 COUNT(常量) 来替代 COUNT() 呢?

    COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别
    前面我们提到过 COUNT(expr) 用于做行数统计,统计的是expr不为NULL的行数,那么 COUNT(列名) 、 COUNT(常量) 和 COUNT(*) 这三种语法中,expr分别是 列名 、 常量 和 * 。

    那么 列名 、 常量 和 * 这三个条件中, 常量 是一个固定值,肯定不为NULL。 * 可以理解为查询整行,所以肯定也不为NULL,那么就只有 列名 的查询结果有可能是NULL了。

    所以, COUNT(常量) 和 COUNT(*)表示的是直接查询符合条件的数据库表的行数。而 COUNT(列名)表示的是查询符合条件的列的值不为NULL的行数。

    除了查询得到结果集有区别之外, COUNT() 相比 COUNT(常量) 和 COUNT(列名) 来讲, COUNT()是SQL92定义的标准统计行数的语法,因为他是标准语法,所以MySQL数据库对他进行过很多优化。

    SQL92,是数据库的一个ANSI/ISO标准。它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)。

    COUNT(*)的优化
    前面提到了 COUNT(*) 是SQL92定义的标准统计行数的语法,所以MySQL数据库对他进行过很多优化。 那么,具体都做过哪些事情呢?

    这里的介绍要区分不同的执行引擎。 MySQL中比较常用的执行引擎就是InnoDB和MyISAM。

    MyISAM和InnoDB有很多区别,其中有一个关键的区别和我们接下来要介绍的 COUNT(*) 有关,那就是 MyISAM不支持事务,MyISAM中的锁是表级锁; 而InnoDB支持事务,并且支持行级锁。

    因为MyISAM的锁是表级锁,所以同一张表上面的操作需要串行进行,所以, MyISAM做了一个简单的优化,那就是它可以把表的总行数单独记录下来,如果从一张表中使用COUNT(*)进行查询的时候,可以直接返回这个记录下来的数值就可以了,当然,前提是不能有where条件。

    MyISAM之所以可以把表中的总行数记录下来供COUNT(*)查询使用,那是因为MyISAM数据库是表级锁,不会有并发的数据库行数修改,所以查询得到的行数是准确的。

    但是,对于InnoDB来说,就不能做这种缓存操作了,因为InnoDB支持事务,其中大部分操作都是行级锁,所以可能表的行数可能会被并发修改,那么缓存记录下来的总行数就不准确了。

    但是,InnoDB还是针对COUNT(*)语句做了些优化的。

    在InnoDB中,使用COUNT(*)查询行数的时候,不可避免的要进行扫表了,那么,就可以在扫表过程中下功夫来优化效率了。

    从MySQL 8.0.13开始,针对InnoDB的 SELECT COUNT(*) FROM tbl_name 语句,确实在扫表的过程中做了一些优化。 前提是查询语句中不包含WHERE或GROUP BY等条件。

    我们知道,COUNT(*)的目的只是为了统计总行数,所以,他根本不关心自己查到的具体值,所以,他如果能够在扫表的过程中,选择一个成本较低的索引进行的话,那就可以大大节省时间。

    我们知道,InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。

    所以,相比之下,非聚簇索引要比聚簇索引小很多,所以 MySQL会优先选择最小的非聚簇索引来扫表。 所以,当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。

    至此,我们介绍完了MySQL数据库对于COUNT(*)的优化,这些优化的前提都是查询语句中不包含WHERE以及GROUP BY条件。

    COUNT(*)和COUNT(1)
    介绍完了 COUNT(*) ,接下来看看 COUNT(1) ,对于,这二者到底有没有区别,网上的说法众说纷纭。

    有的说 COUNT(*) 执行时会转换成 COUNT(1) ,所以COUNT(1)少了转换步骤,所以更快。

    还有的说,因为MySQL针对 COUNT() 做了特殊优化,所以 COUNT() 更快。

    那么,到底哪种说法是对的呢? 看下MySQL官方文档是怎么说的:

    InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

    画重点: same way , no performance difference 。 所以,对于COUNT(1)和COUNT(*),MySQL的优化是完全一样的,根本不存在谁比谁快!

    那既然 COUNT(*) 和 COUNT(1) 一样,建议用哪个呢?

    建议使用 COUNT(*) ! 因为这个是SQL92定义的标准统计行数的语法,而且本文只是基于MySQL做了分析,关于Oracle中的这个问题,也是众说纷纭的呢。

    COUNT(字段)
    最后,就是我们一直还没提到的COUNT(字段),他的查询就比较简单粗暴了,就是进行全表扫描,然后判断指定字段的值是不是为NULL,不为NULL则累加。

    相比 COUNT() , COUNT(字段) 多了一个步骤就是判断所查询的字段是否为NULL,所以他的性能要比 COUNT() 慢。

    总结
    本文介绍了COUNT函数的用法,主要用于统计表行数。主要用法有 COUNT(*) 、 COUNT(字段) 和 COUNT(1) 。

    因为 COUNT() 是SQL92定义的标准统计行数的语法,所以MySQL对他进行了很多优化,MyISAM中会直接把表的总行数单独记录下来供 COUNT() 查询,而InnoDB则会在扫表的时候选择最小的索引来降低成本。当然,这些优化的前提都是没有进行where和group的条件查询。

    在InnoDB中 COUNT(*) 和 COUNT(1) 实现上没有区别,而且效率一样,但是 COUNT(字段) 需要进行字段的非NULL判断,所以效率会低一些。

    因为 COUNT() 是SQL92定义的标准统计行数的语法,并且效率高,所以请直接使用 COUNT() 查询表的行数!

    参考资料:

    https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_count

    About Me
    ——————————————————————————————————————————
    ● 本文作者:小麦苗,部分内容整理自网络,若有侵权请联系小麦苗删除
    ● 本文在itpub、博客园、CSDN和个人微信公众号( xiaomaimiaolhr)上有同步更新
    ● 本文itpub地址: http://blog.itpub.net/26736162
    ● 本文博客园地址: http://www.cnblogs.com/lhrbest
    ● 本文CSDN地址: https://blog.csdn.net/lihuarongaini
    ● 本文pdf版、个人简介及小麦苗云盘地址: http://blog.itpub.net/26736162/viewspace-1624453/
    ● 数据库笔试面试题库及解答: http://blog.itpub.net/26736162/viewspace-2134706/
    ● DBA宝典今日头条号地址: http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826
    ——————————————————————————————————————————
    ● QQ群号: 230161599 、618766405
    ● 微信群:可加我微信,我拉大家进群,非诚勿扰
    ● 联系我请加QQ好友 ( 646634621 ),注明添加缘由
    ● 于 2019-10-01 06:00 ~ 2019-10-31 24:00 在西安完成
    ● 最新修改时间:2019-10-01 06:00 ~ 2019-10-31 24:00
    ● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
    ● 版权所有,欢迎分享本文,转载请保留出处
    ——————————————————————————————————————————
    小麦苗的微店https://weidian.com/s/793741433?wfr=c&ifr=shopdetail
    小麦苗出版的数据库类丛书http://blog.itpub.net/26736162/viewspace-2142121/
    小麦苗OCP、OCM、高可用网络班http://blog.itpub.net/26736162/viewspace-2148098/
    小麦苗腾讯课堂主页https://lhr.ke.qq.com/
    ——————————————————————————————————————————
    使用微信客户端扫描下面的二维码来关注小麦苗的微信公众号( xiaomaimiaolhr
    及QQ群(DBA宝典)、添加小麦苗微信, 学习最实用的数据库技术。
    在这里插入图片描述
    ——————————————————————————————————————————

    展开全文
  • 如何理解count=count++,count的值不变

    千次阅读 多人点赞 2021-05-14 18:09:47
    能进来的朋友肯定跟我一样对于count = count++的结果很不解,希望看完你有收获。 先看一段代码 public class CountTest { public static void main(String[]args) { int count = 0; //初始化count为0 ...

    能进来的朋友肯定跟我一样对于count = count++的结果很不解,希望看完你有收获。

    先看一段代码

    public class CountTest {
    	
    	public static void main(String[]args) {
    		
    		int count = 0;             //初始化count为0
    		for(int i=1;i<=100;i++) {  //遍历100次
    			count = count++;  
    		}
    		System.out.println("count = "+count);  //输出count
    	}
    }

    代码中,count被初始化为0,然后经历了100次 count=count++ ,那输出的答案肯定等于100呀。后自增不就是这样子的吗。其实不然,答案是 0

    我曾经得出答案等于100的其中一个原因是,count++是后++,肯定是先把count的值赋值给count然后在count+1嘛(错误的),恭喜你,你也跟我一样入坑了。因为我也是这样子想的。

    我确实想了很多种不对头的方式,仍旧无法得出正确答案,当我沉迷于百思不得求解的时候,我开始怀疑了我对于count++的理解。难道不是count先赋给左值然后在+1吗(错误的) ?  对,最后我发现就是这里错了。

    下面是对于我对count = count++的探索。

    1. 后++和 赋值=的优先级。

    我曾经学习C语言和C++的时候,每次遇到j = i++的时候,是这样理解的,首先把i的值赋值给j 然后i=i+1. 现在我发现 ++的运算优先级高的仅此于(),说明++的运算优先级是非常高了,而赋值=的运算优先级很低,低到什么程度,比||都低,那我之前想的先赋值在++,是不是不对劲呀。在绝对高的优先级下似乎=不堪一击?那么难道是先i+1然后赋值给了j吗,那这个不就是j=++i了吗,这哪里是j =i++。笑死,这个时候我就发现我只找到了一半的原因,对于count = count++还在执迷不悟中。于是,我想起了一本红书,《C++面向对象程序设计(第二版)》谭浩强中的运算符重载不是讲过后++吗。没错,就是它!

    2.C++运算符重载能扯到这吗?

    如果真的对于count =count++困扰了很多的(比如我),就一起翻到C++面向对象程序设计中的第138页的那个例子(下面)。当然,网上也有很多对于后置自增运算符重载的实例,你也可以去看看。

    Time Time ::operator ++ (int )
    {
        Time temp(*this);
        sec++;   
        if(sec>=60)
        {
            sec-=60;
            ++minute;
        }
        return temp;
    }

    如果看不懂没关系,注意看的就是好像代码要返回的是一个Time类,然后代码中出现了一个 Time  temp(*this),在sec++,然后返回了temp 。哦豁,用一个临时变量保存了当前的对象本身,然后sec+1了,最后返回了保存的对象本身,之所以要保留对象本身是因为sec+1会导致Time对象本身会改变返回的值。我似乎有一点理解了。它是用了一个临时变量存储了这个对象,然后在返回了这个对象。

    相对于count = count ++的话,就是说用了一个temp保存了count的初始值,然后count+1了,但是赋值给count的是temp .也就是说是先加了然后在赋值的,但又没完全是,赋值的是一个临时保存的count。

    3. 对于j = i++的举例

    下面我也将类比一下j = i++的求解过程。

    public class CountTest {
    	
    	public static void main(String[]args) {
    		
    		int i = 0;
    		int j = 0;
    		j = i++;
    		System.out.println("i = "+i);  //输出为1
    		System.out.println("j = "+j);  //输出为0
    		
    	}
    }

    i,j初始化都为0 ,首先出现了一个int temp 变量保留了i(=0)的值,然后i =i+1 ,最后temp赋值给了 j。就没了。 j变成了初始值的i,i变成i+1了,

    j = i++类比于count = count++,就是出现了temp保存了count的初始值,然后count+1了,最后temp赋值给了count。右值count的值在++之前被保存到了temp,然后右值的count本来自身要+1,就是count=1了,但到最后要完成count=赋值操作,把temp保存的count初始值又赋值给了左值。就像count变了,但又没变 ;

    因此在实际的编程可不要犯了这个小细节,导致程序运行不尽人意哦。

    上述就是我对于count = count++的思考,希望对你有用。

    上述只适用于java环境。在c/c++环境中,不同编译器会导致对于该代码有自己的处理方式,会导致运行结果不同。

     

     

     

    展开全文
  • 1.应用场景 能适合场景地使用更加合适搞高效的sql 2.学习/操作 ... 并可查看mysql手册-->...COUNT(DISTINCT) 3.问题 TBD 4.参考 http://kimi.it/156.html 后续补充 ... ...

    1.应用场景

    能适合场景地使用更加合适搞高效的sql

    2.学习/操作

    暂先参见 http://kimi.it/156.html

    并可查看mysql手册-->索引-->COUNT(DISTINCT)

     

    补充:

    2.1 Q: SELECT COUNT(*) > SELECT COUNT(1) > SELECT COUNT(具体字段)
    之前看到的,好像Mysql对count(*)做了单独的优化。

     

    A:关于COUNT()的效率是一个很好的问题,欢迎探讨:
    在MySQL InnoDB存储引擎中,COUNT(*)和COUNT(1)都是对的所有结果进行的COUNT。

    如果有WHERE子句,则是对所有符合筛选条件的数据行进行统计。

    如果没有WHERE子句,则是对数据表的数据行数进行统计。


    因此COUNT(*)和COUNT(1)本质上没有区别,执行的复杂度都是O(N),也就是采用全表扫描,进行循环+计数的方式进行统计。


    如果是MySQL MyISAM存储引擎,统计数据表的行数只需要O(1)复杂度,这是因为每张MyISAM的数据表都有一个meta信息有存储了row_count值。而一致性由表级锁来保证。而InnoDB支持事务,采用行级锁和MVCC机制,所以无法像MyISAM一样,只维护一个row_count变量。因此就需要采用扫描全表,进行循环+计数的方式来完成统计。


    需要注意的是,在实际执行中COUNT(*)和COUNT(1)执行时间可能略有差别,不过你还是可以把这两个在执行效率上看成是相等的。

    另外在InnoDB引擎中,如果是采用COUNT(*)和COUNT(1)来统计数据行数,要尽量采用二级索引。
    因为主键采用的索引是聚簇索引,聚簇索引包含的信息多,明显会大于二级索引(非聚簇索引)。
    对于查找具体的行来说,采用主键索引效率更高。而对于COUNT(*)和COUNT(1)这种,不需要查找具体的行,只是统计行数来说,系统会自动采用占用空间更小的二级索引来进行统计。
    如果有多个二级索引的时候,会使用key_len小的二级索引进行扫描。当没有二级索引的时候,才会采用主键索引来进行统计。

    优化总结:
    1、一般情况下:COUNT(*) = COUNT(1) > COUNT(字段)
    所以尽量使用COUNT(*),当然如果你要统计的是就是某个字段的非空数据行数,那另当别论。毕竟执行效率比较的前提是要结果一样才行。
    2、如果要统计COUNT(*),尽量在数据表上建立二级索引,系统会自动采用key_len小的二级索引进行扫描,这样当我们使用SELECT COUNT(*)的时候效率就会提升,有时候提升几倍甚至更高都是有可能的。

     

    下面有不同观点:

    https://mp.weixin.qq.com/s/6UCFfKs-uthShpP1-7jf-Q  //你还在认为 count(1) 比 count(*) 效率高?

     

    验证:

    过程如下:

    先创建五张表, 数据量分别为 一百, 一千, 一万, 十万, 一百万.

    -- 数据量100 [一百]
    DROP TABLE IF EXISTS `count_hundred`;
    CREATE TABLE IF NOT EXISTS  `count_hundred` (
      `id` bigint unsigned NOT NULL AUTO_INCREMENT,
      `a` bigint DEFAULT NULL,
      `b` bigint DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

     

    -- 数据量1000 [一千]
    DROP TABLE IF EXISTS `count_thousand`;
    CREATE TABLE IF NOT EXISTS  `count_thousand` (
      `id` bigint unsigned NOT NULL AUTO_INCREMENT,
      `a` bigint DEFAULT NULL,
      `b` bigint DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


    -- 数据量10000 [一万]
    DROP TABLE IF EXISTS `count_ten_thousand`;
    CREATE TABLE IF NOT EXISTS  `count_ten_thousand` (
      `id` bigint unsigned NOT NULL AUTO_INCREMENT,
      `a` bigint DEFAULT NULL,
      `b` bigint DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

     

    -- 数据量100000 [十万]
    DROP TABLE IF EXISTS `count_one_hundred_thousand`;
    CREATE TABLE IF NOT EXISTS  `count_one_hundred_thousand` (
      `id` bigint unsigned NOT NULL AUTO_INCREMENT,
      `a` bigint DEFAULT NULL,
      `b` bigint DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

     

    -- 数据量1000000 [一百万]
    DROP TABLE IF EXISTS `count_million`;
    CREATE TABLE IF NOT EXISTS  `count_million` (
      `id` bigint unsigned NOT NULL AUTO_INCREMENT,
      `a` bigint DEFAULT NULL,
      `b` bigint DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

     

    结果:

     

    插入数据:

    使用存储过程进行插入, 过程省略. 其中十万条记录用时大概十几分钟,  一百万记录用时TBD

    其中执行时间如下:

    CALL batch_insert_data_proc('count_hundred', 100);  /* 查询: 0.328  秒. */

    CALL batch_insert_data_proc('count_thousand', 1000);  /* 查询: 3.172 秒. */

    CALL batch_insert_data_proc('count_ten_thousand', 10000);  /* 查询: 31.937 秒. */

    CALL batch_insert_data_proc('count_one_hundred_thousand', 100000);  /* 查询: 14分04 秒. */

    CALL batch_insert_data_proc('count_million', 1000000);  /* 查询: 两个多小时. */ 

     

    Note:

    推荐直接使用MySQL自带的客户端程序执行.

     

    导出sql文件用时[含数据]

     

    后面才知道: 一百万记录插入完毕.

    具体原因: TBD

    同时可以看到各个SQL文件的大小:

     

    由上可初步知道:

    数据量小的时候, 执行时间几乎是按照数据量倍数增长.

    但是数据量在突破一万以上, 执行时间将陡增, 不在简单按照几何规律.

     

     

    详情参考:

    https://blog.csdn.net/william_n/article/details/82977406  //MySQL 批量插入 - 实践

    https://blog.csdn.net/william_n/article/details/108144127 //MySQL - 存储过程 [Stored Procedure] - 学习/实践

     

    开始查询验证

    数据量为100时:

    SELECT COUNT(*) FROM `count_hundred`;
    SELECT COUNT(1) FROM `count_hundred`;
    SELECT COUNT(id) FROM `count_hundred`;
    SELECT COUNT(a) FROM `count_hundred`;
    SELECT COUNT(b) FROM `count_hundred`;

     

    验证1: 列名为主键,count(列名)会比count(1)快

    结论:

    否, 列名为主键,count(列名)会比count(1)与count(*), count(二级索引列),  count(普通字段列) 慢. 后几者效率/速度可认为一致.

     

     

    数据量为1000时:

    SELECT COUNT(*) FROM `count_thousand`;
    SELECT COUNT(1) FROM `count_thousand`;
    SELECT COUNT(id) FROM `count_thousand`;
    SELECT COUNT(a) FROM `count_thousand`;
    SELECT COUNT(b) FROM `count_thousand`;

     

    验证1: 列名为主键,count(列名)会比count(1)快

    结果:

    查询时间维度: count(主键列)  > count(1) = count(*) = count(二级索引列) = count(普通字段列).

     

     

    数据量为10000时:

    SELECT COUNT(*) FROM `count_ten_thousand`;
    SELECT COUNT(1) FROM `count_ten_thousand`;
    SELECT COUNT(id) FROM `count_ten_thousand`;
    SELECT COUNT(a) FROM `count_ten_thousand`;
    SELECT COUNT(b) FROM `count_ten_thousand`;

     

    验证1: 列名为主键,count(列名)会比count(1)快

    结果:

    查询时间维度: count(主键列)  = count(1) = count(*) = count(二级索引列) = count(普通字段列).

     

    数据量为100000时:

    SELECT COUNT(*) FROM `count_one_hundred_thousand`;
    SELECT COUNT(1) FROM `count_one_hundred_thousand`;
    SELECT COUNT(id) FROM `count_one_hundred_thousand`;
    SELECT COUNT(a) FROM `count_one_hundred_thousand`;
    SELECT COUNT(b) FROM `count_one_hundred_thousand`;

     

    验证1: 列名为主键,count(列名)会比count(1)快

    结果:

    查询时间维度: count(主键列)  = count(1) < count(*)  < count(二级索引列) = count(普通字段列).

     

    数据量为1000000时:

    SELECT COUNT(*) FROM `count_million`;
    SELECT COUNT(1) FROM `count_million`;
    SELECT COUNT(id) FROM `count_million`;
    SELECT COUNT(a) FROM `count_million`;
    SELECT COUNT(b) FROM `count_million`;

     

    验证1: 列名为主键,count(列名)会比count(1)快

    结果:

    查询时间维度: count(主键列)  = count(1) < count(*)  < count(二级索引列) < count(普通字段列).

     

     

     

    2.2 TBD

     

    后续补充

    ...

    3.问题/补充

    1.如果数据集都是百万条记录的,如果直接导入sql文件到MySQL比较慢。  //20200903 周四

    如果先做以下设置会大大提高导入的速度:

    SET GLOBAL unique_checks=0;
    SET GLOBAL innodb_flush_log_at_trx_commit=0;
    SET GLOBAL sync_binlog=0;

    当然这不是SQL的问题,是数据库工作方式的问题,不在本课讨论范围内,只是提供大家参考,节省准备的时间。

    导入完成以后记得把所有设置都改回1。

    4.参考

    http://kimi.it/156.html

    https://time.geekbang.org/column/article/102111

    https://mp.weixin.qq.com/s/6UCFfKs-uthShpP1-7jf-Q  //你还在认为 count(1) 比 count(*) 效率高?

    https://blog.csdn.net/william_n/article/details/82977406  //MySQL 批量插入 - 实践

    https://blog.csdn.net/william_n/article/details/108144127 //MySQL - 存储过程 [Stored Procedure] - 学习/实践

    后续补充

    ...

     

     

     

    展开全文
  •   ...一:Count(*)、Count(1)、Count(543)或者无论Count(‘anything’)只要在Count中指定非NULL表达式,结果没有任何区别。因此当你指定Count(*)或者Coun... 博文 来自: qq_27127145的...
  • Select count(*)、Count(1)、Count(0)的区别和执行效率比较   前言       记得很早以前就听说,在使用count的时候要用count(1)而不要用count(*),因为使用count(*)的时候会对所有的...
  • 文章目录count(可空字段)count(非空字段)与count(主键 id)count(1)count(\*)性能对比结论 注:下面的讨论和结论是基于 InnoDB 引擎的。 首先要弄清楚 count() 的语义。count() 是一个聚合函数,对于返回的结果集,一...
  • Mysql中使用count加条件统计

    万次阅读 多人点赞 2019-06-02 10:34:26
    最近发现在处理Mysql问题时,count()函数频繁上镜,常常出现在分组统计的情景下,但是有时候并不是使用group by分好组就可以直接统计了,比如说一个常见的需求,统计每个班级男生所占的比例,这种情况一般会按照班级...
  • 关于数据库中行数统计,无论是MySQL还是Oracle,都有一个函数可以使用,那就是COUNTCOUNT MySQL官网给出的解释是: 1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。结果是一个BIGINT值。 ...
  • 深入理解RabbitMQ中的prefetch_count参数

    千次阅读 2020-10-17 14:03:44
    前提在某一次用户标签服务中大量用到异步流程,使用了RabbitMQ进行解耦。其中,为了提高消费者的处理效率针对了不同节点任务的消费者线程数和prefetch_count参数都做了调整和测...
  • 本篇博客将更新count、distinct、count(distinct)这几个新学到的Elasticsearch关于查询的方法。 1. Count计算 在项目中,count也算是一个比较常用的方法。之前项目中有需要用到,都是基于查询所有的方法,直接取...
  • MySQL中count(1)、count(*) 与 count(列名) 的执行区别

    万次阅读 多人点赞 2019-11-04 20:13:01
    1、count(1) and count(*) 当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count()用时多了! 从执行计划来看,count(1)和count()的效果是一样的。但是在表做过分析之后,count(1)会比count(*)的用时少...
  • 在实习,跑数据中,边跑边检查,我用的上面三个检查数据,小姑娘给我写了个SQL如下:问了下小姑娘count(1)是什么意思,没回答很明白(或许我没听很明白),那到底:count(*),count(1)有什么区别? ...
  • Column count doesn't match value count at row 1; Column count doesn't match value count at row 1; 原因: 插入时的数据个数与表中的字段个数不一致,问题基本都出在Insert语句中 以 LOL 结构表为测试表为例...
  • count(*)、count(1)、count(column) 的区别

    千次阅读 2021-07-22 09:26:08
    count(*)、count(1)、count(column) 的区别 count(column)对特定的列的值具有的行数进行计算,不包含NULL值。 count(1)跟count(主键)一样,只扫描主键。 count(*)跟count(非主键)一样,扫描整个表。明显前者更快一些...
  • Linux 参数之 max_map_count

    千次阅读 2020-10-13 17:01:57
    文章目录Linux 参数之 max_map_count1、原文2、译文3、解读4、如何理解程序设计中的 side-effect Linux 参数之 max_map_count 1、原文 “This file contains the maximum number of memory map areas a process may...
  • COUNT函数暗藏玄机

    千次阅读 2019-11-29 08:51:25
    关于数据库中行数统计,大家一定会想到COUNT函数,但这个函数却暗藏着玄机。 2.常见问题 COUNT有几种用法 ? COUNT(字段名)和COUNT(*)的查询结果有什么不同 ? COUNT(1)和COUNT(*)之间有什么不同 ? COUNT(1)和...
  • SCAN和HSCAN命令 SCAN命令如下: SCAN cursor [MATCH pattern] [COUNT count] [TYPE type] // 返回值如下: // 1. cursor,数值类型,下一轮的起始游标值,0代表遍历结束 // 2. 遍历的结果集合,列表 ...
  • 理解 PostgreSQL 的 count 函数的行为

    千次阅读 2019-04-16 03:28:39
    关于 count 函数的使用一直存在争议,尤其是在 MySQL 中,作为流行度越来越高的 PostgreSQL 是否也有类似的问题呢,我们通过实践来理解一下 PostgreSQL 中 count 函数的行为。 构建测试数据库 创建测试数据库,并...
  • SELECT COUNT语句三种用法

    万次阅读 2019-10-24 15:07:21
    数据库查询相信很多人都不陌生,所有经常有人调侃程序员就是CRUD专员,这所谓的CRUD指的就是数据库的增删改查。...但是,就是这个常用的COUNT函数,却暗藏着很多玄机,尤其是在面试的时候,一不小心就会...
  •  记得很早以前就有人跟我说过,在使用count的时候要用count(1)而不要用count(*),因为使用count(*)的时候会对所有的列进行扫描,相比而言count(1)不用扫描所有列,所以count(1)要快一些。当时是对这一结论深信不疑...
  • count(1)测试,sql语句如下: select count(1) from ums_member; 结果如下: count(*)测试,sql语句如下: select count(*) from ums_member; 结果如下: count(主键)测试,sql语句如下: select count(id) ...
  • count distinct

    千次阅读 2019-03-28 15:07:57
    有时候做报表写sql需要用到去重,一般都是考虑到grouy by,distinct,但是我之前还真没有用到过 count distinct ,在此记录一下,虽然有的人说占内存,效率问题,但是确实是一个知识点。 SELECT COUNT(DISTINCT ...
  • select count(*) 底层究竟做了什么?

    千次阅读 2019-04-06 22:53:33
    在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表的存储引擎,在此前提下,COUNT( * )操作的时间复杂度为O(N),其中 N 为表的行数。 而MyISAM表中可以快速取到表的行数。这些实践经验的背后是...
  • vue3使用vue-count-to组件

    千次阅读 热门讨论 2020-12-22 11:20:14
    数据可视化大屏开发的过程中,需要实现一种滚动数字的效果,在使用vue2时,使用vue-count-to完全没有问题,功能也比较完善(滚动时长,开始值,结束值,前缀,后缀,千分隔符,小数分隔符等等),但是在vue3中使用会...
  • count(0)和count(1)的区别? count(0)和count(1)的区别? count(0)和count(1)的区别?
  • PageHelper自定义count

    千次阅读 2019-10-16 09:19:37
    web页面的查询功能太复杂,pageHelper自动生成的count语句相当于在查询语句外包一层count,查询速度比较慢。需要优化count语句,所以才想起来自定义count语句。 版本要求 5.0.4版本及以上 <dependency> <...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,079,439
精华内容 1,231,775
关键字:

count