留学网站模板,小白网站建设教程,互联网公司网站建设ppt模板下载,服饰工厂网站建设count#xff08;*#xff09;为什么这么慢#xff1f;#xff1f;#xff1f;
在不同的MySQL引擎中#xff0c;count#xff08;*#xff09;有不同的实现方式#xff0c;MyISAM引擎将一个表的总行存在了磁盘上#xff0c;需要的时候会直接返回#xff0c;但InnoD…count*为什么这么慢
在不同的MySQL引擎中count*有不同的实现方式MyISAM引擎将一个表的总行存在了磁盘上需要的时候会直接返回但InnoDB需要遍历全表累加计算。这里说的是没有加where条件的若加了where限制条件MyISAM也会变慢。
那么为什么InnoDB不喝MyISAM一样把总数存起来呢
因为InnoDB是并发控制的无法准确返回有多少行比如说线程A启动事务查询总行数线程B启动事务插入一条数据后查询总行数线程C启动一个单独语句插入一条记录后查询总行数这个三个线程同时启动因为提交事务的时间不一样所以查询出来返回的行数也是不同的。
InnoDB是索引组织表主键的叶子节点是数据普通索引的叶子节点是主键值所以普通索引的树是比主键树小的所以在保证逻辑正确的前提下尽量减小扫描的数据量是设计数据库的通用法则之一。
使用show table status来解决
在InnoDB存在这show table status这个命令这个命令会返回一个table_rows用于返回有多少行虽然这样很快但是返回结果是及其不准确的误差40%-50%之间它也使用了采样估算的方法所以是不准确的这个命令返回的行数数据也不推荐使用。
使用缓存系统来解决
将Reids放在缓存系统当中当被添加入一行的时候Reids1减少一行的时候相应的Reids-1。这种情况下操作都很快但是存在缓存系统可能会失去更新的问题。
因为Reids不能永久保存下来所以得将它找个地方把这个值永久的保存下来我们若在数据行中添加了一行Reids异常重启了将这个操作丢失了我们就得单独去数据页中进行全表遍历得到count的值赋给Reids因为异常重启不是经常出现的现象所以偶尔一次的全表遍历也是可以接受的。
我们抛开异常重启不谈它在逻辑上也存在着问题比如
1. A线程插入数据RB线程读Redis数查询最近100条记录线程A将Redis加1
2.线程A将Redis加1B线程读Redis数查询最近100条记录线程A插入数据R
这里的两种情况是线程A也就是Reids的操作顺序如果是1查询出有新纪录但是Redis没有加1第二种虽然加一了但是查询不出新的记录这里虽然Reids可以正常运行下去但是逻辑上是存在着问题的
使用数据库来解决
我们将计数直接放到数据库当中一张单独的表中首先这解决了系统崩溃数据丢失的问题因为InnoDB是支持崩溃后恢复数据的。那么我们如何解决上面的逻辑问题其实答案很简单使用事务来解决上面我们使用缓存系统是因为两个线程提交的时间不同导致了最后的结果不同那么我们现在将计数表加1不提交这个事务然后开启下一个事务即为读计数表查询100条记录因为前一个事务并没有提交所以读到的计数表并不会变化而且查询到的100条记录中也没有新的记录我们将后面这个事务提交然后再回到前一个事务中对表进行插入操作后提交第一个事务这样逻辑上就是一致的了。