讲了这么多,可能有的人又要问了研究SQL*Net message from client对DBA而言有何意义?
答:可以大致估算服务器与客户端间的网络传输效率
我们挑选一张百万级记录的大表ca_mms_file来做测试
---session 1: 执行大表的扫描,设置arraysize=100,ad._rec_sid表用于记录sid信息
create table ad.rec_sid (sid number,serial# number);
truncate table ad.rec_sid;
sqlplus -S system/asdf3_14@shzwbcv1 << EOF > /dev/null
insert into ad.rec_sid select s.sid,s.serial# from v\$session s,v\$process p where s.sid=sys_context('userenv','sid') and s.paddr=p.addr;
commit;
set arraysize 100
select * from ad.ca_mms_file;
EOF
---session 2: 执行下列过程,保持对于session 1的持续统计
while [ true ]
do
sqlplus -S '/as sysdba' << EOF
set feedback off
set serveroutput on
declare
v_sql2 varchar2(2000):='select ev.sid,event,total_waits,time_waited from v\$session_event ev,ad.rec_sid rs where ev.sid=rs.sid and event in (''SQL*Net message from client'')';
v_event varchar2(300);
v_total_waits number;
v_sid number;
v_time_waited number;
begin
execute immediate v_sql2 into v_sid,v_event,v_total_waits,v_time_waited;
dbms_output.put_line(v_event||' sid: '||v_sid||' total_waits:'||v_total_waits||' time_waited:'||v_time_waited);
end;
/
EOF
sleep 1
done
SQL*Net message from client sid: 2362 total_waits:42 time_waited:1725
SQL*Net message from client sid: 2362 total_waits:44 time_waited:1842
SQL*Net message from client sid: 2362 total_waits:46 time_waited:1961
SQL*Net message from client sid: 2362 total_waits:48 time_waited:2080
SQL*Net message from client sid: 2362 total_waits:50 time_waited:2194
SQL*Net message from client sid: 2362 total_waits:52 time_waited:2299
SQL*Net message from client sid: 2362 total_waits:54 time_waited:2412
SQL*Net message from client sid: 2362 total_waits:56 time_waited:2530
。。。省略了部分输出
可以大致计算出返回的速率为(2530-1725)/(56-42)*10=575ms,因为arraysize=100,575ms是指每100条记录的传输时间,严格来575ms=服务器从PGA里抓取100条记录耗时+100条记录传输到客户端的耗时,值得一提的是因session 1将输出重定义到了/dev/null,所以这个575ms并未包含写入磁盘的事件,如果将Session 1的输出重定向到磁盘上的某个文件,那么时长会因为包含了IO响应而明显延长,以下是将/dev/null替换为一个文件路径后的输出,可以看出100条记录的处理时长增加到了1191ms,其中一半的时长消耗在了IO上
SQL*Net message from client sid: 2362 total_waits:26 time_waited:1507
SQL*Net message from client sid: 2362 total_waits:26 time_waited:1507
SQL*Net message from client sid: 2362 total_waits:27 time_waited:1634
SQL*Net message from client sid: 2362 total_waits:28 time_waited:1756
SQL*Net message from client sid: 2362 total_waits:29 time_waited:1877
SQL*Net message from client sid: 2362 total_waits:30 time_waited:1998
SQL*Net message from client sid: 2362 total_waits:31 time_waited:2113
SQL*Net message from client sid: 2362 total_waits:32 time_waited:2229
SQL*Net message from client sid: 2362 total_waits:33 time_waited:2341
其实还有一个决定服务器与客户端传输效率的因素,那就是SDU size,下面会有详细阐述
SQL*NET more data to client等待事件:
客户端通过arraysize能够指定服务器每一批次传送给客户端的记录条数,还有一个与此功能类似但更贴近网络层面的参数SDU(Session Data Unit),SDU定义了服务器端一次能够向客户端传送多少个字节,大小范围从512 bytes~65535 bytes。当arraysize指定的行数换算成字节后的值大于SDU设定值时,就会触发SQL*NET more data to client等待。举个例子:
客户端的SQL*Plus里设定了,100行为一批次进行返回
set arraysize 100
客户端的sqlnet.ora里定义了sdu_size=8192 bytes
default_sdu_size=8192
假设每行记录的长度为100bytes,100行的总长度就是10000bytes,比8192要大,所以在访问这100条记录的过程中会触发一次SQL*NET more data to client等待,服务器端会先返回8192bytes给客户端,再返回剩下的1808bytes。当然这一切对于客户端来说是透明的:客户端仍然是以每批次100行的速度从服务器端获取结果,只不过在network层面这100行会被拆分成8192bytes、1808bytes两个包。
---session 1:作为客户端连上database server,创建一个测试表Scott.t12
SQL> create table scott.t12 as select owner,table_name,tablespace_name from dba_tables where rownum<200;
Table created.
SQL> SELECT distinct DBMS_ROWID.rowid_block_number(rowid),DBMS_ROWID.rowid_relative_fno(rowid) from scott.t12;