暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

从客户端到 Oracle DB 的延迟测试:在 sqlplus 和 sqlcl 中获取的最小行数

原创 小小亮 2022-12-15
787

前段时间我写了一篇关于如何计算从 Oracle 数据库中获取一行到客户端的网络延迟的博客。我使用的工具是 sqlcl,因为它只需要 Java,因此不需要安装 Oracle 客户端。有些人用 sqlplus 执行了博客中提供的脚本(也是因为当前版本的 sqlcl 需要 Java 11),只看到 1669 次网络往返,有 5000 行和 arraysize 为 1:

test_netlat@orclcdb1@PDB1> exec dbms_output.put_line(to_char(:roundtrips_end - :roundtrips_begin)||' network round trips.');
1669 network round trips.

test_netlat@orclcdb1@PDB1> exec dbms_output.put_line(to_char((:time_end - :time_begin)*10)||' ms elapsed time.');
790 ms elapsed time.

test_netlat@orclcdb1@PDB1> exec dbms_output.put_line(to_char((:db_time_end - :db_time_start)/1000)||' ms DB time.');
165.841 ms DB time.

test_netlat@orclcdb1@PDB1> exec dbms_output.put_line(to_char(round((((:time_end - :time_begin)*10)-((:db_time_end - :db_time_start)/1000))/(:roundtrips_end - :roundtrips_begin),3))||' ms latency per round trip.');
.374 ms latency per round trip.

test_netlat@orclcdb1@PDB1> exec dbms_output.put_line('--> (Elapsed Time - DB Time) / network round trips');
--> (Elapsed Time - DB Time) / network round trips

备注:在 sqlplus 测试期间,rowprefetch 被设置为默认值 1。

使用 sqlcl,我可以看到许多网络往返次数接近预期的 5000:

SQL> exec dbms_output.put_line(to_char(:roundtrips_end - :roundtrips_begin)||' network round trips.');
4953 network round trips.

SQL> exec dbms_output.put_line(to_char((:time_end - :time_begin)*10)||' ms elapsed time.');
2340 ms elapsed time.

SQL> exec dbms_output.put_line(to_char((:db_time_end - :db_time_start)/1000)||' ms DB time.');
987.403 ms DB time.

SQL> exec dbms_output.put_line(to_char(round((((:time_end - :time_begin)*10)-((:db_time_end - :db_time_start)/1000))/(:roundtrips_end - :roundtrips_begin),3))||' ms latency per round trip.');
.273 ms latency per round trip.

SQL> exec dbms_output.put_line('--> (Elapsed Time - DB Time) / network round trips');
--> (Elapsed Time - DB Time) / network round trips

那么用sqlplus的1669次网络往返和用sqlcl的4953次网络往返怎么解释呢?

可以使用 sql_trace 检查获取的行数:

set feed only
alter session set sql_trace=true;
select filler from tlat ;
alter session set sql_trace=false;
set feed on

使用 19.16.x 运行时,跟踪文件显示以下行。针对 19.16 数据库的 sqlplus:

FETCH #139731510199544:c=67,e=66,p=0,cr=3,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=20585748787
FETCH #139731510199544:c=9,e=9,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=20585749126
FETCH #139731510199544:c=7,e=7,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=20585749293
FETCH #139731510199544:c=8,e=8,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=20585749521
FETCH #139731510199544:c=8,e=8,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=20585749706
FETCH #139731510199544:c=0,e=8,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=20585749874
...

重要的是信息“r=”。第一次提取提取了 2 行,所有后续提取提取了 3 行。

使用 sqlcl(版本 22.3.1.0),我可以看到第一次提取时提取了 50 行,然后一次提取了预期的 1 行:

FETCH #140181223387392:c=52,e=52,p=0,cr=3,cu=0,mis=0,r=50,dep=0,og=1,plh=3090445234,tim=5975977699
FETCH #140181223387392:c=17,e=17,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=5975978365
FETCH #140181223387392:c=0,e=19,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=5975978679
FETCH #140181223387392:c=0,e=13,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=5975978968
FETCH #140181223387392:c=13,e=13,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=5975979473
FETCH #140181223387392:c=13,e=13,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=5975979909
...

因此 19c 中的 sqlplus 的最小提取大小(数组大小)为 3,除了第一次提取,sqlcl 提取预期的 1 行,除了第一次提取,它需要 50 行。

备注:在 sqlplus 的早期版本中,arraysize 的最小值是 2,第一次提取 1 行。例如在 12.1.0.2 或 12.2.0.1 中:

FETCH #139833692592448:c=0,e=60,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=422087587
FETCH #139833692592448:c=0,e=23,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=422088651
FETCH #139833692592448:c=0,e=16,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=422089371
FETCH #139833692592448:c=0,e=15,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=422090092

在 18c 中它改变了:

FETCH #140635627289560:c=62,e=61,p=0,cr=3,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=559611770
FETCH #140635627289560:c=22,e=22,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=559612282
FETCH #140635627289560:c=15,e=14,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=559612368
FETCH #140635627289560:c=34,e=34,p=0,cr=1,cu=0,mis=0,r=3,dep=0,og=1,plh=3090445234,tim=559612583

12.2 之前的旧行为。记录在 MOS Note
Pipelined Function with Pipe Row() Pipes out 15 Rows at a Time (Doc ID 1265916.1:https://support.oracle.com/epmos/faces/DocumentDisplay?id=1265916.1 ):

SQL*Plus是用OCI写的,OCI默认预取值为1行。

第一次提取是 1 行,因为在执行时预取了 1 行。
然后它要么执行标量获取,即一个请求的行加上一个预取的行,
要么执行数组获取,因此您会看到例如:

arraysize = 1,取数为:1, 2, 2, …

在初始执行时,它获取一行。因此,在第一次获取调用时,SQL Plus 使其返回该行。在 SQL Plus 进行的第二次提取调用中,要求一行,它必须转到
数据库。这意味着它获取请求的行加上它预取一个额外的行,
你会看到两个获取。SQL*Plus 的下一个提取调用使用预取的行,
然后下一个调用进入数据库并提取另外两个,依此类推。

所以高达12.2。sqlplus 仅依赖于 OCI 的预取机制,因此最小获取大小为 2。为什么我们看到从 18c 开始至少获取 3 行?

我用从 MOS Note
OCI 中获取的 OCI 程序进行了测试:预取行的示例程序(文档 ID 1126015.1:https://support.oracle.com/epmos/faces/DocumentDisplay?id=1126015.1

提供的 c 程序已调整为使用

MAX_FETCH_COUNT 1 –> fetchsize,即sqlplus中的arraysize
prefetch_cnt = 1 –> OCI的prefetch-size

在 19c 中运行程序的跟踪文件如下所示:

FETCH #139759481436136:c=115,e=115,p=0,cr=3,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=17304993374
FETCH #139759481436136:c=0,e=50,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=17304993696
FETCH #139759481436136:c=0,e=73,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=17304994078
FETCH #139759481436136:c=41,e=41,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,plh=3090445234,tim=17304994447

更改 prefetch_cnt = 0 后,每次提取我真的只能看到 1 行:

FETCH #140542285248488:c=93,e=93,p=0,cr=3,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=17507201670
FETCH #140542285248488:c=74,e=74,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=17507202044
FETCH #140542285248488:c=47,e=46,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=17507202294
FETCH #140542285248488:c=28,e=28,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,plh=3090445234,tim=17507202563

从测试中不清楚是什么导致了 18c 中的行为变化。sqlplus in 18c的release notes中描述的新特性好像没有关系。

总结:Blog Script 中提供的用于计算应用程序和 Oracle DB-server 之间的网络延迟的脚本是正确的,但是您可能会认为 sqlplus 和 sqlcl 提供了不同的提取次数(arraysize 为 1),即数据量运输可能有点不同,但这不应该对结果有任何影响。为了 100% 正确地处理延迟,OCI 程序可以使用 fetchsize 为 1 和 prefetch-size 为 0。或者,您可以在 sqlplus 和 sqlcl 中使用 arraysize 为 3 进行测试。


原文标题:Latency test from Client to Oracle DB: Minimum number of rows fetched in sqlplus and sqlcl

原文作者:Clemens Bleile
原文链接:https://www.dbi-services.com/blog/latency-test-from-client-to-oracle-db-minimum-number-of-rows-fetched-in-sqlplus-and-sqlcl/

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论