查数据过多,会把数据库打爆吗

大前提:根据主键查询返回数据

select *  from t

innodb的数据是直接保存在主键索引上的,全表扫描实际上是扫描表t的主键索引。这条语句没有其他判断条件,所以查到的每一行可以直接放到结果集返回给客户端,

实际上,服务端并不需要保存一个完整的结果集,取数据和发数据的流程是这样的:

1.获取一行,写到 net_buffer。这块内存大小是参数 net_buffer_length定义的,默认16K

2.重复获取行,知道net_buffer_length写满,调用网络接口发出去

3.如果发送成功,清空net_buffer,然后继续取下一行,并写入net_buffer

4.如果发送函数返回 EAGAIN 或 WSAEWOULDBLOCK就表示本地网络栈(socket send buffer)写满了,进入等待。知道网络栈重新可写,再继续发送

流程图如下

 流程中,可以看到:

1.一个查询在发送过程中,占用的MYSQL内部的内存最大就是net_buffer_length,不会达到200G

2.socket send buffer也不可能达到200G(默认定义/proc/sys/net/core/wmem_default),如果socket send buffer被写满,就会暂停读数据的流程

也就是说,mysql是边读边发的,这个概念很重要。这就意味着,如果客户端接收的慢,会导致MYSQL服务端由于结果发布出去,这个事务的执行时间边长。

当show full processlist 时,看到许多线程处于 sending to client 这个状态,就意味着要确认是否要返回那么多的结果,这个查询是否可以优化

如果要快速减少这个状态的线程的话,可以将net_buffer_length参数设置为一个更大的值

与sending to client相似的一个状态是sending data,一个查询语句的状态变化为:

1.mysql查询语句进入执行阶段后,首先把状态设置为sending data

2.然后发送执行结果的列相关的信息meta data给客户端

3.再继续执行语句的流程

4.执行完成后,把状态设置为空字符串

查询内存命中率,buffer pool中的:  show engine innodb status  可以看到“Buffer pool hit rate”字样,显示的就是当前的命中率

innodb_buffer_pool_size 小于磁盘数据量是很常见的,如果一个buffer pool 满了,而又要从磁盘读入一个数据页,那肯定要淘汰一个旧的数据页的

LRU算法:为全表扫描的操作量身定制

在 InnoDB 实现上,按照 5:3 的比例把整个 LRU 链表分成了 young 区域和 old 区域。图中 LRU_old 指向的就是 old 区域的第一个位置,是整个链表的 5/8 处。也就是说,靠近链表头部的 5/8 是 young 区域,靠近链表尾部的 3/8 是 old 区域。改进后的 LRU 算法执行流程变成了下面这样。 中状态

1,要访问数据页 P3,由于 P3 在 young 区域,因此和优化前的 LRU 算法一样,将其移到链表头部,变成状态

2。之后要访问一个新的不存在于当前链表的数据页,这时候依然是淘汰掉数据页 Pm,但是新插入的数据页 Px,是放在 LRU_old 处。

3.处于 old 区域的数据页,每次被访问的时候都要做下面这个判断:

若这个数据页在 LRU 链表中存在的时间超过了 1 秒,就把它移动到链表头部;

如果这个数据页在 LRU 链表中存在的时间短于 1 秒,位置保持不变。1 秒这个时间,是由参数 innodb_old_blocks_time 控制的。其默认值是 1000,单位毫秒。

原文地址:https://www.cnblogs.com/byfboke/p/13804400.html