【等待优化】如何定位网络性能问题 ASYNC_NETWORK_IO 等待

【1】问题

【1.1】服务器本地查询很快,远程连接查询很慢

一同事跟我反馈他遇到了一个SQL性能问题,他说全表只有69条记录,客户端执行耗费了两分多钟,这不科学呀。要我分析一下原因并解决。我按照类似表结构,构造了一个案例,测试截图如下所示

【1.2】远程连接查询测试

  clipboard

这个表有13800KB(也就是13M多大小),因为该表将图片保存到数据库(Item_Photo字段为iamge类型),这个是历史原因,暂且不喷这种的设计。

看来这个SQL执行时间长的性能问题不在于IO和SQL本身执行计划是否有问题,而是在网络数据传时间上(服务器与客户端位于异地,两地专线带宽6M,不过很多应用、邮件、系统都依赖此专线)

sp_spaceused 'Item_Test'
 
name               rows     reserved        data        index_size      unused
-----------  -------------  ----------  -------------- ----------- -------------
Item_Test          69      13864 KB      13800 KB           16 KB        48 KB

【1.3】本地连接查询测试

为了验证我的想法,我在服务器本机测试时间为2秒,如下截图所示

  clipboard[1]

【2】分析

【2.1】使用SSMS Include Client Statistics 查看客户端消耗状态

从上面我们知道在客户端执行完该SQL语句,总共耗费了2分23秒。那么客户端的到底获取了多少字节数据,数据传输耗费了多长时间呢? 能否查看这些DETAIL信息呢?

答案是可以。在SSMS工具栏,勾选“Include Client Statistics”或使用快捷键SHIFT+ALT+S,然后执行SQL语句,就能得到如下截图的相关信息。

  clipboard[2]

   

  clipboard[3]

Client Statistics(客户端统计信息)包含三大块:  Query Profile Statistics, Network Statistics, Time Statistics。

这些部分的内容很容易理解,无需多说,那么我们来看看吧

Network Statistics(网络统计信息)
Number of server roundtrips:        服务器往返的次数
TDS packets sent from client:       从客户端发送的TDS数据包(个数)
TDS packets received from server:   从服务端接收的TDS数据包(个数)
Bytes sent from client:             从客户端发送的字节数
Bytes received from server:         从服务器接收的字节数
Time Stattistics:(时间统计信息)
Client processing time:              客户端处理时间
Total execution time:                总执行时间
Wait time on server replies:         服务器应答等待时间

从客户端发送的字节和从服务端接收的数据大小都很清晰、明了,那么数据从服务器端发送给客户端所需的时间这里没有,其实它基本上接近客户端处理时间(Client processing time)。

我们也可以将客户端处理时间权当网络数据传输时间,从上面案例,我们可以看到这个时间耗费了140秒(140132 ms),可以肯定这个SQL性能慢在网络数据传输上,而不是慢在数据库那一块(Server Processing Time).

【2.2】sql server数据发送与接收的大致原理流程图

我们来看看下图,这个是SQL SERVER的请求接收和数据输出的一个大致流程图,当客户端发送请求开始,当服务器接收客户端发来的最后一个TDS包,数据库引擎开始处理请求,请求完成后,将数据发送给客户端,从图中可以看出,客户端接收服务器端返回的数据也是需要一个过程的(或者说时间)

  clipboard[4]

我们在SQL优化过程中,如果一个SQL出现性能问题时,我们应该站在一个全局的角度来分析问题,从CPU资源、网络带宽、磁盘IO、执行计划等多方面来分析,这样才能有助于你分析、定位问题根源。

而不要只要SQL响应很慢时,就一味条件反射式先入为主:这是数据库问题。数据库也不能老背这个黑锅。

【2.3】在 dm_exec_requests 中可以发现 ASYNC_NETWORK_IO 等待

在数据库等待事件中,ASYNC_NETWORK_IO可以从另外一个侧面反映网络性能问题。关于ASYNC_NETWORK_IO等待类型:

This waittype indicates that the SPID is waiting for the client application to fetch the data before the SPID can send more results to the client application.

【3】优化解决

那么回到如何优化这个SQL的问题上来,我们可以从下面几个方面来进行优化。

【3.1】SQL只取必须的字段数据

        像这个案例,其实它根本不需要Item_Photo字段数据,那么我们可以修改SQL,只取我们需要的字段数据,就可以避免这个问题,提高SQL性能,另外根据我的经验,开发人员习惯性使用SELECT *,从不管那些数据是需要还是不需要的,先全部取过来再说,这种习惯性行为确实不是一个好习惯。

【3.2】避免这种脑残设计

      图片应该以文件形式保存在应用服务器上,数据库只保存其路径信息,这种将图片保存到数据库的设计纯属脑残行为。

------------------------------------------------------------分割线-------------------------------------------------------------

看到很多网友说没有给出解决方案和结果,我就很纳闷,解决方法我明明不是已经在上文交代吗,后面陆陆续续好几个都这样说,不淡定了,看来我的表述能力还是有问题,好吧,补充如下:

因为这个案例,根本不需要用到Item_Photo这个字段(保存的图片),那么我就取所需字段就好了,如下所示

  image

  clipboard[2]

如上截图所示,Client processing time(客户端处理时间)为18毫秒,服务器端传送过来的数据只有7512字节,也就是7KB大小。

对比上下两者的差距,我想数据能说明一切了,关于我喷图片保存在数据库的这种设计,出乎我意料,很多人不认同,好吧,不多说也不偏激,自己测试、权衡吧。事实胜于雄辩!

原文地址:https://www.cnblogs.com/gered/p/13597281.html