引言
国庆长假收心之等待事件

闲来无事,和朋友聊天,讨论到SQL*Net类型等待事件,相信大家都遇到过这样一个问题,查询后台等待事件,发现可能95%的会话都处于sql*net message from client 类型等待事件,这是否意味着都在等待客户端响应或者说客户端响应的速度非常慢呢???
显然不是的亲们,v$session_wait本身就是站在cpu的角度来看待等待事件的,这里需要明确一个概念,sql*net message from client要么可能是cpu在进行处理,要么就是处于空闲等待上。今天的主题,和大家聊聊SQL*Net类型等待事件,这里我必须澄清,我不会误人子弟,更不会不懂装懂,更不会把错误的观点和思路强加到任何人身上,选择关注文章的各位读者,如果觉得我说的有问题,随时联系我,个人会加以改正,也请多多包涵。
我的QQ号码为619899746,微信号是duliang198411,手机号码186**8*0*1*,言归正传,文章很短,请您耐心看完
Part
1
SDU 技术指标
在没有进入正式的解决办法之前,我们先来分享几个重要的技术指标,从而帮助大家更方便的去理解SQL*类型等待事件,今天我们讨论的重点放在两个非常常见等待事件上,一个是SQL*Net message to client,另一个是SQL*Net more data to client.
1.1 何为Oracle SDU ?
大家都知道在典型的数据库配置中,Oracle Net在通过网络发送数据之前将数据封装到会话数据单元(SDU)的缓冲区中。
当缓冲区被填充、刷新或应用程序试图读取数据时,Oracle Net会发送每个缓冲区。根据每次发送给Oracle Net的数据量调整SDU缓冲区的大小,可以提高性能、网络利用率和内存消耗。在传输大量数据时,增加SDU大小可以提高性能和网络吞吐量,本质上这一个性能优化的话题。
注意
注意:
SDU全称:session data unit,Oracle Net在通过网络传输数据之前用来放置数据的缓冲区。Oracle Net在请求或缓冲区满时发送缓冲区中的数据。
1.2 网络发送区间定位 ?
向Oracle Net提供的每次发送的数据量称为消息大小。Oracle Net默认的,假设消息大小通常在0到8192字节之间变化,很少大于8192字节。如果这个假设是真的,那么大多数情况下,数据都是使用一个SDU缓冲区发送的。
1.3 SDU的大小如何确定 ?
SDU的大小可以从512字节到65535字节不等。客户机和专用服务器的默认SDU是8192字节。共享服务器的默认SDU是65535字节,所以在1.2部分内容,我只是假设,因为我个人没办法确定各位读者是共享服务器还是专用服务器。
注意
注意:当主要消息大小小于或大于8192时,应该考虑更改SDU大小。SDU大小应该比主要消息大小大70字节。如果主要的消息大小加上70字节超过了最大的SDU,那么应该将SDU设置为将消息大小分成相等部分的最小数量,其中每个部分比SDU大小小70字节。要更改默认值,请更改sqlnet.ora中的DEFAULT_SDU_SIZE参数
1.4 举例说明
如果应用程序发送和接收的大多数消息小于8KB(考虑到开销的70字节),那么将SDU设置为8KB可能会产生良好的结果。如果有足够的内存可用,那么使用SDU的最大值可以最小化Oracle Net服务的系统调用数量和开销。
注意
注意:从Oracle数据库11g开始,Oracle Net Services优化了组件的批量数据传输,比如Oracle SecureFiles lob和Oracle data Guard重做传输服务。在网络参数文件中指定的SDU大小限制不适用于这些批量数据传输。更加详细的内容,大家可以参考https://docs.oracle.com/cd/E18283_01/network.112/e10836/intro.htm#i453017文章
1.5 如何设置数据库SDU的大小 ?
1.5.1
要设置数据库服务器的SDU大小,需要配置sqlnet.ora文件
1.5.2
在sqlnet.ora中配置DEFAULT_SDU_SIZE参数,例如:DEFAULT_SDU_SIZE=8192
1.5.3
如果使用共享服务器进程,则在初始化参数文件中的DISPATCHERS参数中设置SDU大小:
DISPATCHERS="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp))(SDU=8192))
1.5.4
listener.ora设置
SID_LIST_listener_name=
(SID_LIST=
(SID_DESC=
(SDU=8192)
(SID_NAME=duliang)))
注意:前期可以保守设置,sdu为8192即可
Part
2
Round Trip Time网络延迟和带宽 相关建议
2.1
带宽延迟乘积是网络带宽和数据在网络中的往返时间的乘积。确定往返时间的一种简单方法是使用命令,例如从一台主机ping到另一台主机,并使用ping返回的响应时间,这是大家都知道的一种方法。
2.2
举个例子:例如,如果一个网络有一个100 Mbps的带宽和5 ms的往返时间,那么发送和接收缓冲区应该至少(100 * 10 ^ 6)*(5/10 ^ 3)位或大约62.5 kb,下面的方程表示了单位与所涉及因素之间的关系:
100,000,000 bits 1 byte 5 seconds
---------------- x ------ x --------- = 62,500 bytes
1 second 8 bits 1000
===================================
注意
将SEND_BUF_SIZE和RECV_BUF_SIZE至少设置为带宽延迟上限,以确保在发送大量数据时网络带宽得到最佳利用
大致分析一下,说的并不一定准确,因为我网络知识也只是略懂一二,该网络链路的带宽延迟乘积约为64KB。如果用于在主数据库和备用数据库之间传输重做数据的最大 消息是1MB,那么SEND_BUF_SIZE和RECV_BUF_SIZE参数的值可能是1MB。但是,如果平均消息更少,那么64KB的设置应该足以优化可用带宽的使用。
对于大多数网络协议,确保网络连接一端(通常在客户端)的RECV_BUF_SIZE参数等于另一端(通常在服务器端)的SEND_BUF_SIZE参数的值
Part
3
配置I/O缓冲区空间
3.1 可靠的网络协议
可靠的网络协议,如TCP/IP,将数据缓冲到发送和接收缓冲区中,同时从下层和上层协议发送和接收数据。这些缓冲区的大小通过影响流量控制决策而影响网络性能
3.2 RECV_BUF_SIZE & SEND_BUF_SIZE
RECV_BUF_SIZE和SEND_BUF_SIZE参数指定与Oracle Net连接相关联的套接字缓冲区的大小。为了确保连续的数据流和更好地利用网络带宽,使用RECV_BUF_SIZE和 SEND_BUF_SIZE参数指定会话接收和发送操作的I/O缓冲区空间限制。RECV_BUF_SIZE和SEND_BUF_SIZE参数值不必匹配,但应该根据环境设置。
3.3 OCI_PREFETCH_MEMORY
为了获得最佳性能,发送和接收缓冲区的大小应该设置得足够大,以容纳网络连接上可能并发发送的所有数据。对于简单的数据库连接,这通常映射到OCI_PREFETCH_MEMORY大小。
注意
1. 当然啦,小心使用这些参数,因为它们会影响网络和系统性能。这些参数的默认值是特定于操作系统的
2.这些参数支持TCP、带有SSL和SDPs的TCP/IP等等,具体的安装指导意见,关注oracle官网即可,这里我们不做过多赘述。
3.4 在客户机上配置I/O缓冲区空间:
在客户机上配置I/O缓冲区空间:

注意
注意:
1.一般只设置RECV_BUF_SIZE参数就足够了。如果客户端正在发送大型请求,那么还可以设置SEND_BUF_SIZE参数。这些参数是在客户机的sqlnet.ora文件中设置的
3.5 在服务器上配置I/O缓冲区大小
在服务器上配置I/O缓冲区大小
因为数据库服务器向客户机写入数据,所以在服务器端设置SEND_BUF_SIZE参数通常就足够了。如果数据库服务器正在接收大型请求,那么还可以设置RECV_BUF_SIZE参数。
要配置数据库服务器,就需要在监听文件中设置缓冲区空间大小

3.6 下面是sqlnet.ora文件的配置
RECV_BUF_SIZE=65536
SEND_BUF_SIZE=65536
3.7 TDU
TDU是Oracle Net中用于将数据分组的默认数据包大小。理想情况下,TDU参数应该是SDU参数的倍数,这里对TDU不做太多介绍了亲们。感兴趣去oracle官网看吧
3.8 客户端或服务器平均等待时间
下面的查询显示了一种从Oracle的角度评估网络性能的方法,其中客户机或服务器的平均等待时间是根据服务器或客户机分别等待消息的时间记录

3.9 客户机和服务器实际传输字节数
下面的查询显示了客户机和服务器进程的平均等待时间以及实际传输的字节数

注意
注意:
1.内容实在太多了,我只粘贴了部分内容
2.经验之谈:
Oracle调优网络使用的关键是尽可能少地使用网络。可能最重要的因素是将SQL语句组合成事务。例如,如果要获取10个行,一次发送10个行的请求比为每一行发送10个请求更有效。由于网络比数据库服务器或客户机慢得多,所以这一点应该是显而易见的。
Part
4
正式进入
SQL*Net message to client
SQL*Net more data to client
等待事件调优环节
基础的一些技术指标介绍完毕以后,我们来进入正式的SQL*Net message to client,另一个是SQL*Net more data to client等待事件调优环节。
注意:
刚才我们已经明确说过SQL*Net类型等待事件的重点,这些等待并不意味着Oracle的等待,而是通常空闲的等待事件或网络等待。
4.1 等待事件说明
当服务器进程向客户端发送数据或消息并等待回复时,就会发生类似SQL*Net message to client等待事件。原则上其实等待时间就是等待TCP响应的时间。这个等待通常被认为是一个空闲的等待事件,因为服务器进程正在等待其他的响应。就调优而言,如果单个等待时间很高,那么很可能无法在服务器上进行改进,而是在其他地方。
如果总等待量很高,但是单个等待量很小,那么等待量可能是由于网络接入的方式问题。
4.2 工作原理猜想
对于SQL*Net事件等待,Oracle使用SDU(会话数据单元,这个技术指标刚才我们介绍过了)写入到TCP套接字缓冲区的SDU缓冲区。
如果数据大于会话数据单元的初始大小,那么需要发送多个数据块。如果有更多的数据要发,那么在每批数据发送后,会话将等待SQL*Net more data to client上。
4.3 如何诊断?
那么如何诊断SQL*Net message to client和SQL*Net more data to client ???
注意:仅仅包括个人看法,诊断等待的最佳方法,我个人认为是运行10046。一个进程或一个sql都可以使用10046跟踪。例如下面一个傻瓜式的简单举例:

注意
注意:
通过10046获得跟踪,如果觉得不好定位,可以TKPROF格式化一下,这里可以看到单个等待'SQL*Net message to client'的时间通常很短(在这种情况下,总等待时间小于1微秒)。等待会被记录下来,但是我们可以清晰的在10046中看到max wait和total waited都是0,等待并不一定是性能问题或引起关注的重点。
4.4 arraysize
如果应用程序使用大量数据,请考虑增加应用程序中的arraysize。如果使用较小的arraysize来获取数据,那么查询将使用多个fetch调用,每个调用都将等待'SQL*net message to client'事件。
4.4.1 何为arraysize ?
SQL*PLus中的默认ARRAYSIZE是15。这将在分析跟踪文件时显示,方法是将返回的行数除以SQLNet往返次数,作为应用程序中使用的默认大小。当向应用程序返回一组值时,
ARRAYSIZE指定要返回的行数。因为这指定了要返回的数组大小,所以它直接影响满足数据请求所需的往返次数。
4.4.2 举例说明

注意:
大致判断一下,总行数是93151行,该表总共有1792个block,那么相当于将近60行数据就占用一个block。

注意:
实际上oracle使用了1639个数据块,我们也可以看到实际上每个数据块存37行,49行,53行数据,都是不等的,这里就不一一列举了。有人会为,那1792个数据块哪里来的,忽悠我呢?来看如下查询


注意:
oracle总共分配了29个extent,其中16个区是以8K数据块为单位,另外13个extent是以128K数据块为单位的,也就是说 (16 * 8) +(13*128)=1792的结果
.........

执行计划

统计信息

注意:
缺省arraysize为15的情况下产生的SQL*Net to client为 5298168
........

执行计划

统计信息

注意:
arraysize调整到200后产生的SQL*Net to client为4249913
........

执行计划

统计信息

注意:
arraysize调整到500后产生的SQL*Net to client为4198916
Part
5
总结
今天通过一些简单的技术指标和大家分享一下sql*net类型等待事件调优的心得,希望通过这篇并不完美的文章可以在日常工作中帮到各位

雁过留影,爱过留心
LOVE

扫描如下QQ群二维码,加入600团队
分享创造价值,分享创造快乐













