MySQL之数据发送流程

x33g5p2x  于2021-10-14 转载在 Mysql  
字(1.5k)|赞(0)|评价(0)|浏览(237)

数据发送流程

MySQL是CS架构的,也就是基于客户端-服务器模式,读取数据流程如下:
1、客户端通过TCP与服务器建立连接
2、客户端通过网络发送一个查询数据包,里面包含了对应的sql语句
3、服务器收到查询数据包后,取出并执行里面的sql语句,将结果通过网络返回给客户端。

这里面有个问题,如果查询一个大规模数据的话,服务器会将所有的数据都读取到内存中吗?会不会把内存都打爆?

其实不是的,MySQL是边读取边发送的。

MySQL没必要把所有数据都读取到内存中,因为数据最终要通过网卡发送出去,网卡不可能一下子把所有数据发送出去,会分批的发送,这样的话,如果把所有数据都放到内存中,只会白白的占用宝贵的内存。

MySQl中每个连接都对应着一个线程,每个线程都对应着一个net_buffer,用来存放要发送给客户端的数据,大小默认是16KB。

1、MySQL首先将数据写入到net_buffer中,直到net_buffer满了或者数据不足16KB。
2、调用系统内核,将net_buffer中的数据通过网卡发送出去,这里会存在内存拷贝,将数据从用户态拷贝到内核态,也就是从net_buffer拷贝到socket_send_buffer
3、发送过程是阻塞的,当发送完毕后,也就是成功发送后,会继续读取数据,放到net_buffer中,就这样循环往复,直到所有数据都发送完毕

这里值得注意的是,因为采用的是TCP连接,如果客户端的读取效率慢的话,对应的数据会一直占用客户端的接收窗口,使接收窗口慢慢的变为0,MySQL服务器的发送窗口的大小是和客户端的接收窗口保持一致的,会造成MySQL的发送窗口变小,甚至变为0,MySQL服务器无法发送数据,因为客户端的接收窗口被之前的数据占满了,无法接收新的数据了。

两种接收模式

客户端有两种接收模式
1、mysql_store_result
客户端将服务器发送的数据一次性读取,然后一次性处理。

2、mysql_use_result
客户端读取读取一行,然后执行对应的业务逻辑,接着在读取一行,也即是读取一行,处理一行

当客户端的业务处理逻辑比较慢的时候,如果使用mysql_use_result会造成客户端一直不读取MySQL服务器发来的下面的数据。因为MySQL采用的是TCP,会导致客户端的TCP的接收窗口慢慢变为0,那么MySQL服务器的发送窗口也会变为0,MySQL服务器无法发送任何数据。这会使连接变成一个长连接,一直毫无意义的占用MySQL服务器的内存资源。

如果有大量的这种客户端请求的话,MySQL的内存会被打爆的。

所以如果客户端如果执行的逻辑比较慢的话,并且接收的数据量不是特别大的话,最好使用 mysql_store_result,先把所有的数据接收了,再慢慢处理。

排序特殊例子

这里我们再说一个特殊情况,如果请求的数据是需要排序的,而且对应的排序字段没有索引,会把所有的数据都读取到内存中,然后在内存中排序。

当数据量大的时候,MySQL会利用rowid排序(如果返回的字段加起来数据量过大,MySQL在内存中只会放入id和待排序字段,这样可以减少内存占用,排好序后利用id重新回表查询)和外部排序(如果待排序的数据过大,将数据分发到磁盘的多个文件中,对多个文件进行单独排序,然后进行归并排序)。对这部分感兴趣的可以看我之前写的文章MySQL之orderby详解

对于大数据排序,我们有两种解决方法:
1、对要排序的字段建立索引,因为索引是有序的,可以直接一条一条的读取,读取之后可以直接返回给客户端。
2、对MySQL请求无序的数据,在客户端进行手动排序。

相关文章

微信公众号

最新文章

更多