Array Fetch Size研究.docx
《Array Fetch Size研究.docx》由会员分享,可在线阅读,更多相关《Array Fetch Size研究.docx(15页珍藏版)》请在冰豆网上搜索。
![Array Fetch Size研究.docx](https://file1.bdocx.com/fileroot1/2022-11/24/7c1d3373-a712-4734-a430-9f9145260c9a/7c1d3373-a712-4734-a430-9f9145260c9a1.gif)
ArrayFetchSize研究
ArrayFetchSize研究
测试环境
不同ArrayFetchSize下的统计输出
查询的工作过程
ArrayFetchSize对网络的影响
ArrayFetchSize对consistentgets的影响
ArrayFetchSize与竞争
ArrayFetchSize与内存
总结
延伸阅读
ArrayFetchSize这个参数决定了客户端一次从数据库获取数据的行数,写过访问Oracle数据库程序的人可能会发现ArrayFetchSize在默认情况下设置的值都比较小,当他把ArrayFetchSize设定值加大之后,自己的程序明显的跑的更快了。
既然越大ArrayFetchSize对于程序运行越快,那为什么默认的ArrayFetchSize值会那么小,多大的ArrayFetchSize值才是个合适的呢?
本文就试图探索下这方面的内容。
top测试环境
1
2
3
4
5
6
7
8
9
ORAINST@orcl>SELECT*FROMv$version;
BANNER
----------------------------------------------------------------
OracleDatabase10gEnterpriseEditionRelease10.2.0.2.0-Prod
PL/SQLRelease10.2.0.2.0-Production
CORE 10.2.0.2.0 Production
TNSforLinux:
Version10.2.0.2.0-Production
NLSRTLVersion10.2.0.2.0-Production
1
2
3
4
oracle@orainst[orcl]:
~$uname-a
Linux2.4.21-50a6smp#1SMPWedOct318:
57:
25PDT2007i686i686i386GNU/Linux
oracle@orainst[orcl]:
~$cat/etc/redhat-release
RedHatEnterpriseLinuxWSrelease3(TaroonUpdate4)
top不同ArrayFetchSize下的统计输出
SQLPlus中可以自由的设定ArrayFetchSize的大小,因此我们的实验都是基于SQLPlus来完成的,实际上不管是什么类型客户端还是自己基于OCI写程序,都是能单独设置ArrayFetchSize的,SQLPlus设置方法为SETARRAYSIZEnumber,默认情况下的ArrayFetchSize大小为15,最大值允许设置的值是5000,可以通过SHOWARRAYSIZE来查看当前使用的值。
现在来建立一个测试表,然后设定不同ArrayFetchSize,在观察不同情况下查询输出的统计数据有什么样的区别。
首先建立测试数据:
1
2
3
4
5
6
7
--创建测试表
ORAINST@orcl>CREATETABLEtASSELECT*FROMall_objects;
Tablecreated.
--表建立完毕之后打开统计输出
ORAINST@orcl>SETAUTOTTRACESTATISTICS
ORAINST@orcl>SETTIMINGON
在表T上面我们没有建立任何的索引,现在我们查询表T中的一行数据,在查询一行数据时,查询的统计数据将不会受到ArrayFetchSize设定值的影响,这种情况下的consistentgets可以认为是对表T做一次全表扫描所必须要读取的块的数量,统计输出结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ORAINST@orcl>select*fromtwhereobject_id=100;
Elapsed:
00:
00:
00.01
Statistics
----------------------------------------------------------
1 recursivecalls
0 dbblockgets
147 consistentgets
0 physicalreads
0 redosize
1205 bytessentviaSQL*Nettoclient
384 bytesreceivedviaSQL*Netfromclient
2 SQL*Netroundtripsto/fromclient
0 sorts(memory)
0 sorts(disk)
1 rowsprocessed
接着尝试不同ArrayFetchSize值下的查询。
ArrayFetchSize为1时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ORAINST@orcl>SETARRAYSIZE1
ORAINST@orcl>SELECT*FROMT;
11284rowsselected.
Elapsed:
00:
00:
00.61
Statistics
----------------------------------------------------------
1 recursivecalls
0 dbblockgets
5712 consistentgets
0 physicalreads
0 redosize
1128755 bytessentviaSQL*Nettoclient
62435 bytesreceivedviaSQL*Netfromclient
5643 SQL*Netroundtripsto/fromclient
0 sorts(memory)
0 sorts(disk)
11284 rowsprocessed
ArrayFetchSize为10时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ORAINST@orcl>SETARRAYSIZE10
ORAINST@orcl>SELECT*FROMT;
11284rowsselected.
Elapsed:
00:
00:
00.30
Statistics
----------------------------------------------------------
0 recursivecalls
0 dbblockgets
1257 consistentgets
0 physicalreads
0 redosize
555604 bytessentviaSQL*Nettoclient
12792 bytesreceivedviaSQL*Netfromclient
1130 SQL*Netroundtripsto/fromclient
0 sorts(memory)
0 sorts(disk)
11284 rowsprocessed
ArrayFetchSize为50时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ORAINST@orcl>SETARRAYSIZE50
ORAINST@orcl>SELECT*FROMT;
11284rowsselected.
Elapsed:
00:
00:
00.24
Statistics
----------------------------------------------------------
0 recursivecalls
0 dbblockgets
369 consistentgets
0 physicalreads
0 redosize
440923 bytessentviaSQL*Nettoclient
2859 bytesreceivedviaSQL*Netfromclient
227 SQL*Netroundtripsto/fromclient
0 sorts(memory)
0 sorts(disk)
11284 rowsprocessed
ArrayFetchSize为100时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ORAINST@orcl>SETARRAYSIZE100
ORAINST@orcl>SELECT*FROMT;
11284rowsselected.
Elapsed:
00:
00:
00.24
Statistics
----------------------------------------------------------
0 recursivecalls
0 dbblockgets
258 consistentgets
0 physicalreads
0 redosize
426572 bytessentviaSQL*Nettoclient
1616 bytesreceivedviaSQL*Netfromclient
114 SQL*Netroundtripsto/fromclient
0 sorts(memory)
0 sorts(disk)
11284 rowsprocessed
ArrayFetchSize为2500时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ORAINST@orcl>SETARRAYSIZE2500
ORAINST@orcl>SELECT*FROMT;
11284rowsselected.
Elapsed:
00:
00:
00.24
Statistics
----------------------------------------------------------
0 recursivecalls
0 dbblockgets
151 consistentgets
0 physicalreads
0 redosize
412856 bytessentviaSQL*Nettoclient
428 bytesreceivedviaSQL*Netfromclient
6 SQL*Netroundtripsto/fromclient
0 sorts(memory)
0 sorts(disk)
11284 rowsprocessed
为了对比的方便,我们将上面的数据汇总在下面的表格里面:
ArrayFetchSize
consistentgets
SQL*Netroundtrips
ElapsedTime
1
5712
5643
00:
00:
00.61
10
1257
1130
00:
00:
00.30
50
369
227
00:
00:
00.24
100
258
114
00:
00:
00.24
2500
151
6
00:
00:
00.24
表1:
不同ArrayFetchSize下统计数据对比
从上面的表中我们很容易就能看出来ArrayFetchSize对于consistentgets,SQL*Netroundtrips,ElapsedTime这三个参数的影响都还是比较大的。
文章的后面几个部分就来一个个的分析这些参数都是怎么被影响的。
top查询的工作过程
由于ArrayFetchSize的存在,客户端的动作可以分解成为下面的几个步骤:
1.向服务器请求ArrayFetchSize行数据
2.等待服务器服务器响应(此时服务器准备相应的数据)
3.从网络接收服务器传送的数据
4.将接收的数据在本地保存
5.检查是否取完所有数据,如果没有则转向第1步,否则完成查询
通过服务器端的10046trace可以大概看到整个过程,现在来重复一下ArrayFetchSize为1和100时的查询,并把查询产生的trace结果保存下来,得到trace的相关语句如下:
1
2
3
4
5
6
7
8
sqlplus"orainst/hello"<SETAUTOTTRACESTATISTICS
SETTIMINGON
altersessionsettracefile_identifier='arraysize01';
altersessionsetevents'10046tracenamecontextforever,level12';
SETARRAYSIZE1
SELECT*FROMT;
EOF
类似的代码将SETARRAYSIZE1换成SETARRAYSIZE100再重复一次,这样可以在udump目录中看到两个名字中包含arraysize的trace文件,下面是我的运行结果:
1
2
3
4
5
oracle@orainst[orcl]:
/dumps-01/databases/orcl/udump
$ll-h
total1.8M
-rw-r--r-- 1oracle dba 1.6MMar 814:
35orcl_ora_27337_arraysize01.trc
-rw-r--r-- 1oracle dba 64KMar 814:
35orcl_ora_27341_arraysize100.trc
打开其中的名字为orcl_ora_27337_arraysize01.trc的文件,可以看到类似下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PARSINGINCURSOR#6len=15dep=0uid=36oct=3lid=36tim=1238338811398144hv=1406298530ad='3b4835fc'
SELECT*FROMT
ENDOFSTMT
PARSE#6:
c=0,e=25457,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=1238338811398132
BINDS#6:
EXEC#6:
c=0,e=62,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1238338811398383
WAIT#6:
nam='SQL*Netmessagetoclient'ela=2driverid=1650815232#bytes=1p3=0obj#=-1tim=1238338811398436
FETCH#6:
c=0,e=141,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,tim=1238338811398635
WAIT#6:
nam='SQL*Netmessagefromclient'ela=537driverid=1650815232#bytes=1p3=0obj#=-1tim=1238338811399242
WAIT#6:
nam='SQL*Netmessagetoclient'ela=1driverid=1650815232#bytes=1p3=0obj#=-1tim=1238338811399324
......这里有几万条类似的记录......
FETCH#6:
c=0,e=46,p=0,cr=1,cu=0,mis=0,r=2,dep=0,og=1,tim=1238338812564076
WAIT#6:
nam='SQL*Netmessagefromclient'ela=84driverid=1650815232#bytes=1p3=0obj#=-1tim=1238338812564204
WAIT#6:
nam='SQL*Netmessagetoclient'ela=1driverid=1650815232#bytes=1p3=0obj#=-1tim=1238338812564252
FETCH#6:
c=0,e=48,p=0,cr=1,cu=0,mis=0,r=1,dep=0,og=1,tim=1238338812564291
WAIT#6:
nam='SQL*Netmessagefromclient'ela=378driverid=1650815232#bytes=1p3=0obj#=-1tim=1238338812564744
***SESSIONID:
(30.30827)2010-03-0814:
35:
44.067
上面记录中显示的每次的FETCH操作就是服务器端准备数据的时间,等待消息为”SQL*Netmessagetoclient”的WAIT行就是向客户端传送数据并等待响应的过程,在ArrayFetchSize设置为100的那个trace文件中,我们还能看到类似于”SQL*Netmoredatatoclient”的等待时间,这个也是服务器还在向客户端传送数据的一个事件。
在这里,每一次的FETCH操作都会对应一次“向服务器请求ArrayFetchSize行数据”的操作(注意:
当ArrayFetchSize为1时SQLPlus会按照值为2的情况去取数据),只有最后一次的FETCH不一样,最后一次FECTH是为了确定已经没有数据可取的,因此在表T一共有11284行记录,所以对应的FETCH操作就共有11284/2+1=5643次,而ArrayFetchSize为100是FETCH的数量一共是roundup(11284/100)+1=114,这个数据我们可以通过运行下列命令看到:
1
2
#这个命令会处理生成的全部包含array字串的trace文件
$fornamein`lsorcl*array*.*`;dotkprof$name$name.txt;done
运行完了以后打开orcl_ora_27337_arraysize01.trc.txt可以看到下面的信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SELECT*FROMT
call count cpu elapsed disk query current rows
------------- ------------------------------------------------ ----------
Parse 1 0.00 0.02 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 5643 0.21 0.25 0 5712 0 11284
------------- ------------------------------------------------ ----------
total 5645 0.21 0.28 0 5712 0 11284
--中间省略了一部分数据--
Elapsedtimesincludewaitingonfollowingevents:
Eventwaitedon Times Max.Wait TotalWaited
---------------------------------------- Waited ---------- ------------
SQL*Netmessagetoclient