您的位置:首页 > 其它

Arraysize的设置以及对查询性能的影响

2011-03-20 17:33 323 查看
Arraysize是sql*plus中可以设置的一个参数,这个参数设置的意思表示,sql*plus一次可以从数据库服务器端获取的记录行数。
show arraysize
arraysize 15
可以看到,在SQL*plus中,默认设置是15。有效值是1-5000。按照《Oracle9i Database Performance Tuning Guide and Reference Release 2》的说法,当这个值的设置超过100后,对性能改进基本上不会有多少帮助了。
在OCI和OCCI中,都可以设置这个参数,
例如,在OCCI中设置这个参数的函数是:setPrefetchRowCount()。

做个简单的实验:
create table t as select * from all_objects;
set autotrace traceonly statistics;

set arraysize 2
select * from t;

统计信息
----------------------------------------------------------
288 recursive calls
0 db block gets
25300 consistent gets
682 physical reads
0 redo size
8135852 bytes sent via SQL*Net to client
273691 bytes received via SQL*Net from client
24848 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set arraysize 5
select * from t;

统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
10477 consistent gets
0 physical reads
0 redo size
6197846 bytes sent via SQL*Net to client
109703 bytes received via SQL*Net from client
9940 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set arraysize 10
select * from t;

统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
5588 consistent gets
0 physical reads
0 redo size
5551876 bytes sent via SQL*Net to client
55044 bytes received via SQL*Net from client
4971 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set arraysize 15
select * from t;

统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
3952 consistent gets
0 physical reads
0 redo size
5336466 bytes sent via SQL*Net to client
36817 bytes received via SQL*Net from client
3314 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set arraysize 100
select * from t;

统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
1178 consistent gets
0 physical reads
0 redo size
4970386 bytes sent via SQL*Net to client
5841 bytes received via SQL*Net from client
498 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set arraysize 500
select * from t;

统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
786 consistent gets
0 physical reads
0 redo size
4918776 bytes sent via SQL*Net to client
1474 bytes received via SQL*Net from client
101 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set arraysize 5000
select * from t;

统计信息
---------------------------------------------------------
0 recursive calls
0 db block gets
697 consistent gets
0 physical reads
0 redo size
4907076 bytes sent via SQL*Net to client
484 bytes received via SQL*Net from client
11 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49693 rows processed

set autotrace off

从统计信息可以看出,查询同样的结果集,当arraysize增加时,主要有几个方面的变化:
第一:consistent gets减少,表示查询需要的逻辑I/O减少;
第二:数据请求在网络间的往返次数减少,一次传送的数据多了,往返次数自然会减少;
第三:网络传输中的数据总流量减少,这主要是因为减少了网络传输中非结果集数据的开销。

但并不能因此就说,arraysize设置为5000是最好的,因为这样会导致客户端和服务器端使用更多的内存,并且,因为服务器必须一次性准备好5000行记录才能提供给终端,会导致终端一会在等待,一会又突然处理一大批数据,导致性能出现不稳定。

关于arraysize为什么会减少逻辑I/O,可以这样理解:当查询获取一个批量的记录时,其中有可能一部分记录处在同一个块中,如果缓存较少的结果集,Oracle下次不得不访问同一个块获取某些记录,如果缓存足够大,则在一次获取中,就可以把同一个块中符合条件的记录都获取到了,就避免重复访问同一个块,从而减少了逻辑I/O。

再做一个实验,这个实验来源于《Oracle9i&10g编程艺术》,从这个实验可以看出,arraysize的增加对于查询物理存储无序的表的逻辑I/O影响不大。
先创建一个有序表:
create table colocated ( x int, y varchar2(80) );
begin
for i in 1 .. 100000
loop
insert into colocated(x,y)
values (i, rpad(dbms_random.random,75,'*') );
end loop;
end;
/
alter table colocated
add constraint colocated_pk
primary key(x);
begin
dbms_stats.gather_table_stats( user, 'COLOCATED', cascade=>true );
end;
/

再创建一个无序表:
create table disorganized
as
select x,y
from colocated
order by y;
alter table disorganized
add constraint disorganized_pk
primary key (x);
begin
dbms_stats.gather_table_stats( user, 'DISORGANIZED', cascade=>true );
end;
/
运行下列脚本:
set arraysize 15
select * from colocated a15 where x between 20000 and 30000;
set arraysize 100
select * from colocated a100 where x between 20000 and 30000;

tkprof报告显示:
(a15)
Rows Row Source Operation
------- ---------------------------------------------------
10001 TABLE ACCESS BY INDEX ROWID COLOCATED (cr=1452 pr=0 pw=0 time=100109 us)
10001 INDEX RANGE SCAN COLOCATED_PK (cr=689 pr=0 pw=0 time=40047 us)(object id 53215)

(a100)
Rows Row Source Operation
------- ---------------------------------------------------
10001 TABLE ACCESS BY INDEX ROWID COLOCATED (cr=344 pr=0 pw=0 time=90081 us)
10001 INDEX RANGE SCAN COLOCATED_PK (cr=124 pr=0 pw=0 time=30043 us)(object id 53215)

Arraysize为15时,对索引执行了689个逻辑I/O,对表执行了763(1452-689)个逻辑I/O,arraysize为100时,对索引执行了124个逻辑I/O,对表执行了220个逻辑I/O。这说明因为表有序,所以在一个块中有较多需要的记录,增加arraysize可以获得良好效果。

set arraysize 15
select /*+ INDEX(a15 DISORGANIZED_PK) */* from disorganized a15 where x between 20000 and 30000;
set arraysize 100
select /*+ INDEX(a100 DISORGANIZED_PK) */* from disorganized a100 where x between 20000 and 30000;

tkprof报告显示:
(a15)
Rows Row Source Operation
------- ---------------------------------------------------
10001 TABLE ACCESS BY INDEX ROWID DISORGANIZED (cr=10685 pr=0 pw=0 time=180134 us)
10001 INDEX RANGE SCAN DISORGANIZED_PK (cr=689 pr=0 pw=0 time=40336 us)(object id 53218)

(a100)
Rows Row Source Operation
------- ---------------------------------------------------
10001 TABLE ACCESS BY INDEX ROWID DISORGANIZED (cr=10119 pr=0 pw=0 time=160110 us)
10001 INDEX RANGE SCAN DISORGANIZED_PK (cr=124 pr=0 pw=0 time=30334 us)(object id 53218)

Arraysize为15时,对索引执行了689个逻辑I/O,对表执行了9996(10685-689)个逻辑I/O,arraysize为100时,对索引执行了124个逻辑I/O,对表执行了9995个逻辑I/O。减少的逻辑I/O基本上都来自于索引,索引本身是有序的。这说明因为表无序(表的记录信息无序),所以在一个块中有较少条需要的记录,增加arraysize效果不明显。

参考文献:
《Oracle高效设计》
《Oracle9i&10g编程艺术》
《Oracle9i Database Performance Tuning Guide and Reference Release 2》
《Oracle C++ Call Interface Programmer's Guide 10g Release 2》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: