Oracle 网络层等待事件深度解析:SQL*Net message from/to client

Oracle 网络层等待事件深度解析:SQL*Net message from/to client

在生产环境中,我们经常会看到 AWR/ASH 中高居榜首的两个事件:

  • SQL*Net message from client
  • SQL*Net message to client

SQL*Net message from client:到底在等什么?

官方定义

字段说明
事件名SQL*Net message from client
本质前台进程等待客户端发送下一条指令
P1客户端网络驱动类型(Thin/OCI/JDBC/OCI over TCPS …)
P2期望接收的字节数
超时无,直到客户端真的发消息

三种典型场景

  1. 真正的 Idle 一个交互式会话,用户正在屏幕前思考下一步操作。 ➜ 无需处理,不属于“性能问题”。
  2. 批处理“伪 Idle” PL/SQL 批处理程序把逻辑写在客户端(Java/Python),每取 1 行就计算一次,导致服务端 99% 时间都在等客户端。 ➜ 把计算搬到服务端(存储过程、BULK COLLECT + FORALL),或至少一次取 fetchSize = 1000
  3. 网络往返放大 应用框架默认 autoCommit=true,每条 DML 后都有一次往返。 ➜ 设置 useLocalTransaction=true、批量提交。

如何量化

  • AWR:SQL*Net message from client平均等待时长 高,但 单次等待 低 → 批处理循环。
  • ASH:同一 sql_id 的等待分布,如果堆在 from client,说明 客户端代码 是瓶颈。

SQL*Net message to client:消息送不出去

字段说明
事件名SQL*Net message to client
本质服务端已准备好数据,但客户端或网络链路“吃不下”
P1客户端网络驱动类型
P2本次发送的字节数
超时

常见根因

  1. 客户端 GC/CPU 飙高 JVM Full GC 时,应用线程无法读取 socket,服务端只能挂起。 ➜ 监控 JVM,调 GC 或加大 SDU/TDU 减少往返。
  2. 网络抖动/带宽不足 大量 LOB/LONG RAW 导致 packet loss,TCP 重传。 ➜ 网络团队抓包;数据库侧启用 SDU=65535TDU=65535TCP.NODELAY=YES
  3. 错误 JDBC 设置 defaultRowPrefetch=10,结果集 100 万行时,服务端一次次“塞”数据。 ➜ 调大 defaultRowPrefetch(100~1000)或改用游标式流。

一条 SQL 引发的“血案”

现象

AWR 报告 SQL*Net message from client 占 DB Time 60%,单次仅 0.3 ms,次数 180 M。

定位

ASH 抽取 sql_id = 7r3m5... 对应 Java 方法 com.foo.Bar.processRow(),发现伪代码:

while (rs.next()) {
   total += rs.getBigDecimal("amount");
}

解决

在 Java 端把循环改为:

SELECT SUM(amount) INTO :1 FROM ...

一次往返搞定,事件直接消失。


行动清单(Checklist)

  • AWR/ASH 先看 平均等待时长 vs 次数
  • 若是批处理,优先 BULK COLLECT + FORALL
  • 若是交互式,确认是否真 Idle
  • 检查 JDBC 参数:defaultRowPrefetchfetchSizeautoCommit
  • 网络层:ping, traceroute, tcpdump, oradebug tracefile_name 抓 SDU/TDU
  • 客户端资源:GC 日志、CPU、内存

下次再看到这两个事件,别再一股脑把锅甩给网络——多数时候,真正的瓶颈在应用和数据库之间的 交互模式

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部