MySQL原理count为什么这么慢

白癜风用什么药最好 http://disease.39.net/bjzkbdfyy/170816/5629059.html
导读:我想你平时在开发系统的时候,你可能会经常统计一些表的总记录数。比如你平时在维护者某个电商系统的订单表,某天你们老板来找你,说让你给他查一下开公司到现在所有订单数。你肯定会想到利用count聚合函数去统计。我想你的SQL应该是这样的:selectcount(*)fromorder;那你是否想过,如果订单表很大的话这条SQL会非常耗时耗内存。今天我们就来重新认识一下count的方方面面。实验表解释NOTE:由于排版原因,我们创建表语句就不在这里写了,如有需要请评论区留言。我们有三张测试表:order1、order2、order3,且每张表都有abcd四个字段。并且表中都有一万条一模一样的数据,而且还另外插入了两条:(a,b,c,d)values(null,,,),(,,,);第一张表:索引:PRIMARYKEY(`id`),KEY`idx_a`(`a`),KEY`idx_b`(`b`)引擎:InnoDB第二张表:索引:PRIMARYKEY(`id`),KEY`idx_a`(`a`),KEY`idx_b`(`b`)引擎:MyIsAm第三张表:索引:PRIMARYKEY(`id`)引擎:InnoDBcount(*)和count(a)的区别注意:当count(?)统计某一列时,这列的NULL值是不统计的。比如我们在表order1(原始数据)中对a列插入了NULL值,在执行selectcount(a)fromorder1是不会统计的,此时计算出的值任然是。而我们已经在表中插入了2条数据了。注意:当count(*)统计表总数时,无论某列某条数据是否包含NULL,都会进行统计。当我们执行selectcount(*)fromorder1,此时返回的是2,表中全部的数据。count(*)统计的是所有行,所以当我们想知道某表所有行的时候,最好用count(*)。MyIsAm与InnoDBcount(*)一起来分析一下两大存储引擎count(*)的区别到底在哪里。执行速度不同只执行selectcount(*)fromtable,MyIsAm执行速度远远高与InnoDB。注意只是存储的count(*),没有任何where条件。实现方式不同MyIsAm会把表总行数存储到磁盘上,在需要的时候会直接返回结果。而InnoDB每次统计都会重新从引擎表里一行一行扫描计算。实战演示:我们在order2(使用的MyIsAm引擎)表中执行explainselectcount(*)fromorder2;返回的结果中Extra字段内容为:Selecttablesoptimizedaway关键字,表示是从MyISAM引擎维护的准确行数上获取到的统计值。我们在order1(使用InnoDB引擎)表中执行explainselectcount(*)fromorder1;Extra字段显示Usingindex,发现使用的是b字段的索引idx_b,并且扫描行数是,表示会遍历b字段的索引树去计算表的总量。在这一节中我们这一这么总结:MyISAM会维护表的总行数,放在磁盘中,如果有count(*)的需求,直接返回这个数据。但是InnoDB就会去遍历普通索引树,计算表数据总量。思考:在order1表中,为什么count(*)执行的是idx_b索引而不是主键索引呢?下面一起来看看吧MySQL5.7.18前后count(*)区别在5.7.18以前,MySQL是通过扫描表的聚簇索引来统计总行数。在5.7.18后改成了遍历最小可用二级索引统计总行数。如果二次索引不存在才会扫描聚簇索引。不过这里也要注意一点:如果索引中的记录不都在缓存池的话,count(*)也是会比较久的。原因是InnoDB二级索引树的叶子节点上存放的是主键,而主键索引树的叶子节点上存放的是整行数据,所以二级索引树比主键索引树小。因此优化器基于成本的考虑,优先选择的是二级索引。所以count(主键)其实没count(*)快。count(1)与count(*)比谁更快前面说说了count(*)不管有没有NULL都会对行做全部统计。count(1)作为一个恒定的表达式也是会统计所有结果的。结论:count(*)和count(1)统计结果没有差别,explain执行结果都是一样的。不同count用法count(id):InnoDB会遍历全部表中的数据,然后将id返回到server层,server层得到id判断id是不是为空,如果是真实的id则按行累加,将结果返回client。count(1):InnoDB会遍历整张表,但不会取值。server层对于返回的每一行会放一个数字1进去,判断是不是我空,也是按行累加返回client。count(字段):如果字段定义为notnull,则按行累加,如果允许有null,则会把值取出来判断一下是不是null,将不是null的值累加返回。count(*):MySQL对它专门做了优化,上面我们讲了,不同存储引擎对它的优化方式不同,count(*)会返回全部行,不管某列是不是null。统计总数按效率排序:count(字段)count(id)count(1)约等于count(*)。总结这节课我们首先讲解了count(*)和count(a)的区别,然后我们举例说明了两者的差异性,并且做了对比总结,最后比较了count(1)与count(*)以及不同count使用方法。思考问题(下节课解答):了解forceindex(idx_a)执行selectcount(*)fromorder1forceindex(idx_a);结果和执行selectcount(*)fromorder1;是否一致?为什么?哪些方法可以加快count(*)?结语:欢迎大家把好文章分享给更多的朋友,如果对你有帮助请转发收藏+


转载请注明:http://www.aierlanlan.com/rzdk/7202.html