赞
踩
主机内存只有100G,现在对一个200G的大表进行扫描,会不会把数据库的内存用完。
假设现对一个200G的InnoDB表db1,做一个全表扫描,当然要把扫描结果保存到客户端。
InnoDB的数据时保存在主键索引上的,所以全表扫描实际上是扫描表t的主键索引,最后返回给客户端。
返回的结果集并不是完整的,因为MySQL是边读边发的
流程为:1.获取一行写到net_buffer当中,net_buffer是由net_buffer_length定义的,默认为16k。
2.重复获取知道net_buffer写满,调用网络接口发送出去。
3.若是发送成功,就清空net_buffer,然后继续读取下一行写入net_buffer
4.若发送函数返回EAGAIN或WSAEWOULDBLOCK就表示本地网络栈写满,直到网络栈重写可写,再继续重复操作。
一个查询在发送过程当中,占用MySQL内部最大内存就是net_buffer这么大,并不会达到200G。这意味着,若客户端接收慢,MySQL就会由于结果发送不出去导致事务执行的时间变长。
若是客户端不读socket receive buffer中的内容,然后再show processlist中可以看到state处于一个Sending to client的状态。
对于线上业务来说,若是一个查询的返回结果不会很多,就可以在客户端使用一个-quick参数就可以使用,mysql_use_result这个方法,读一行处理一行。当然前提是查询返回结果不多,若是看到多个线程都处于Sending to client,可以将net_buffer_length设置为一个更大的值。
MySQL查询语句在进入执行阶段之后,首先将状态设置为Sending data,再继续执行语句的流程,执行完成后就会将状态改为空字符串。
也就是说在一个线程处于“等待客户端的状态”才会显示未Sending to client,Sending data是正在执行。
InnoDB内存的作用是保持更新结果在配合redo log避免了随机写盘,内存的数据页是在BUffer Pool中管理的。
BUffer Pool还有一个加速功能,因为有WAL机制,当时事务要提交的时候,有一个查询要读该内存页,就可以直接读,因为这个时候,内存页是最新的,直接读内存页就可以了,无需将redo log应用到数据页当中再读取。
Buffer Pool对于查询加速效果还有一个重要的指标:内存命中率,一般情况下,内存命中率要在99%以上。
InnoDB Buffer Pool大小是由参数innodb_buffer_pool_size决定的,一般设置为物理内存的60%-80%。
innodb_buffer_pool_size小于磁盘的数据量很常见,若一个buffer pool满了,就要淘汰一个旧数据页来更新一个新数据页。InnoDB通过改进LRU算法来实现这一目标。
LRU算法:假设内存当中有P1,P2,P3,P4,P5这么多数据页,是以链表形式保存的,P1是刚刚更新的所以在头部,这个时候有请求访问P3,P3就会被移动到头部,现在要更新一个数据页,因为内存满了,要删除一个,就会删除尾巴的P5数据页。
InnoDB改进:InnoDB将其进行改进,以5:3将空间分为young和old区域,young区域中的操作和原LRU算法相同。
在old区域每次被访问的时候做如下的操作:
1.若这个数据页在LRU链表中存在时间超过1秒,就移动到头部。
2.若是短于1秒,位置保持不变
时间有参数Innodb_old_blacks_time控制,单位为毫秒,默认一秒。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。