Oracle逻辑读的示例分析


这篇文章给大家分享的是有关Oracle逻辑读的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

1.物理读(physical
read)
数据块第一次读取到,就会缓存到buffer cache 中,而第二次读取和修改该数据块时就在内存buffer cache 了
以下是例子:
1.1第一次读取:C:”Documents and Settings”Paul Yi>sqlplus “/as
sysdba”
SQL*Plus: Release 9.2.0.4.0 – Production on Thu Feb 28 09:32:04
2008
Copyright (c) 1982, 2002, Oracle Corporation.All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 – Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 – ProductionSQL> set autotrace traceonly
SQL> select * from test;
Execution Plan
———————————————————-
0SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=8)
10TABLE ACCESS (FULL) OF ‘TEST’
(Cost=2 Card=4 Bytes=8)

Statistics
———————————————————-
175recursive calls
0db block gets
24consistent gets
9physical
reads–9个物理读

0redo size
373bytes sent via SQL*Net to client
503bytes received via SQL*Net from client
2SQL*Net roundtrips to/from client
2sorts (memory)
0sorts (disk)
1rows processed1.2第二次读取SQL> select * from test;
Execution Plan
———————————————————-
0SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=8)
10TABLE ACCESS (FULL) OF ‘TEST’
(Cost=2 Card=4 Bytes=8)

Statistics
———————————————————-
0recursive calls
0db block gets
7consistent gets
0physical
reads–没有发生物理读了,直接从buffer cache
中读取了

0redo size
373bytes sent via SQL*Net to client
503bytes received via SQL*Net from client
2SQL*Net roundtrips to/from client
0sorts (memory)
0sorts (disk)
1rows processed1.3数据块被重新读入buffer
cache ,这种发生在
如果有新的数据需要被读入Buffer
Cache中,而Buffer
Cache又没有足够的空闲
空间,Oracle就根据LRU算法将LRU链表中LRU端的数据置换出去。当这些数据被再次访问到时,需要重新从磁盘读入。SQL> alter
session set events ‘immediate trace name
flush_cache’;–
清空数据缓冲区Session altered.SQL> select *
from test;

Execution Plan
———————————————————-
0SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=8)
10TABLE ACCESS (FULL) OF ‘TEST’
(Cost=2 Card=4 Bytes=8)

Statistics
———————————————————-
0recursive calls
0db block gets
7consistent gets
6physical
reads–又重新发生了物理读

0redo size
373bytes sent via SQL*Net to client
503bytes received via SQL*Net from client
2SQL*Net roundtrips to/from client
0sorts (memory)
0sorts (disk)
1rows processed2.逻辑读(buffer read)逻辑读指的就是从(或者视图从)Buffer
Cache中读取数据块。按照访问数据块的模式不同,可以分为即时读(Current Read)和一致性读(Consistent
Read)。注意:逻辑IO只有逻辑读,没有逻辑写。
即时读即时读即读取数据块当前的最新数据。任何时候在Buffer
Cache中都只有一份当前数据块。即时读通常发生在对数据进行修改、删除操作时。这时,进程会给数据加上行级锁,并且标识数据为“脏”数据。
SQL> select *
from test for update;

Execution Plan
———————————————————-
0SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=8)
10FOR UPDATE
21TABLE ACCESS (FULL) OF ‘TEST’ (Cost=2 Card=4 Bytes=8)
Statistics
———————————————————-
0recursive calls
1db block
gets

14consistent gets
0physical reads
252redo size
386bytes sent via SQL*Net to client
503bytes received via SQL*Net from client
2SQL*Net roundtrips to/from client
0sorts (memory)
0sorts (disk)
1rows processedSQL>一致性读Oracle是一个多用户系统。当一个会话开始读取数据还未结束读取之前,可能会有其他会话修改它将要读取的数据。如果会话读取到修改后的数据,就会造成数据的不一致。一致性读就是为了保证数据的一致性。在Buffer
Cache中的数据块上都会有最后一次修改数据块时的SCN。如果一个事务需要修改数据块中数据,会先在回滚段中保存一份修改前数据和SCN的数据块,然后再更新Buffer
Cache中的数据块的数据及其SCN,并标识其为“脏”数据。当其他进程读取数据块时,会先比较数据块上的SCN和自己的SCN。如果数据块上的SCN小于等于进程本身的SCN,则直接读取数据块上的数据;如果数据块上的SCN大于进程本身的SCN,则会从回滚段中找出修改前的数据块读取数据。通常,普通查询都是一致性读。
下面这个例子帮助大家理解一下一致性读:会话1中:SQL> select *
from test;
ID
———-
1000SQL> update test
set id=2000;
1 row updated.会话2中:SQL> set
autotrace on

SQL> select *
from test;
ID
———-
1000
Execution Plan
———————————————————-
0SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=8)
10TABLE ACCESS (FULL) OF ‘TEST’
(Cost=2 Card=4 Bytes=8)

Statistics
———————————————————-
0recursive calls
0db block gets
9consistent
gets没有事物做update时 是 7 consistent
gets说明多了2个consistent
gets这2个是要从回滚段中获取的

0physical reads
52redo size
373bytes sent via SQL*Net to client
503bytes received via SQL*Net from client
2SQL*Net roundtrips to/from client
0sorts (memory)
0sorts (disk)
1rows processedSQL>Oracle性能调优中,逻辑读是个很重要的度量值,它不仅容易收集,而且能够告诉我们许多关于数据库引擎工作量的信息。逻辑读是在执行SQL语句的时候从高速缓存中读取的块数。逻辑读在Oracle调优中有四个好处:(1)逻辑读是受制于CPU能力的操作,因而,很好的反映了CPU的使用情况。(2)逻辑读可能导致物理读,因而,通过减少逻辑读的数量,很可能会降低I/O操作次数。(3)逻辑读是受制于串行的操作,既然经常要考虑多用户负载的优化,最小化逻辑读将有利于避免扩展性问题。(4)逻辑读的数量可以通过SQL跟踪文件和动态性能视图在SQL语句以及执行计划级别获得。下面就来详细的讲述下逻辑读相关的知识,以作为自己学习的一个总结。
我们都知道,数据块是oracle最基本的读写单位,但用户所需免费云主机域名要的数据,并不是整个块,而是块中的行,或列.当用户发出SQL语句时,此语句被解析执行完毕,就开始了数据的抓取阶段,在此阶段,服务器进程会先将行所在的数据块从数据文件中读入buffercache,这个过程叫做物理读.物理读,每读取一个块,就算一次物理读.当块被送进buffercache后,并不能立即将块传给用户,因为用户所需要的并不整个块,而是块中的行.从buffercache的块中读取行的过程,就是逻辑读.为了完成一次逻辑读,服务器进程先要在hash表中查找块所在的buffercache链.找到之后,需要在这个链上加一个cachebufferchains闩,加闩成功之后,就在这个链中寻找指定的块,并在块上加一个pin锁.并释放cachebufferchains闩.然后就可以访问块中的行了.服务器进程不会将块中所有满足条件的行一次取出,而是根据你的抓取命令,每次取一定数量的行.这些行取出之后,会经由PGA传给客户端用户.行一旦从buffercache中取出,会话要释放掉在块上所加的PIN.本次逻辑读就算结束.如果还要再抓取块中剩余的行,服务器进程要再次申请获得cachebufffer链闩.再次在块上加PIN.这就算是另外一次逻辑读咯.也就是说,服务器进程每申请一次cachebuffer链闩,就是一次逻辑读.而每次逻辑读所读取的行的数量,可以在抓取命令中进行设置.
逻辑读和Cachebufferchains闩关系密切,TOM曾有文章提到,进程每申请一次Cachebufferchains闩,就是一次逻辑读。但是,逻辑读并不等同于Cachebufferchains闩,每次逻辑读,在9i中至少需要获得两Cachebufferchains闩。逻辑读是指在Hash表中定位块的这个过程。

下面是我的测试
步1:建立测试表:
createtablejj_one(idnumber(5),namechar(40));

步2:插入100行
begin
foriin1..100loop
insertintojj_onevalues(i,’aaa’);
endloop;
end;
/

或:insertintojj_oneselectrownum,’aaa’fromdba_objectswhererownum

步3:显示一下表中行的分布
sid=10pid=11>selectbk,max(id),min(id)from(selectdbms_rowid.rowid_block_number(rowid)bk,idfromjj_one)groupbybk;

BKMAX(ID)MIN(ID)
——————————
42594811
4259510082

可以看到,表共占两个块,ID从1到81的行在块42594中,ID从82到100的行在42595中。

步4:设备批量读取参数为15
sid=10pid=11>setarraysize15
因为9i或10g中的默认值都是15,如果并没有更改过这个设置,此步也可省去。

步5:查看1行:
sid=11pid=12>setautottracestat
sid=11pid=12>select*fromjj_onewhereid

统计信息
———————————————————-
0recursivecalls
6consistentgets
0physicalreads
458bytessentviaSQL*Nettoclient
372bytesreceivedviaSQL*Netfromclient
2SQL*Netroundtripsto/fromclient
1rowsprocessed
(省略无关行)

逻辑读为6

步6:查询15行以内:
sid=11pid=12>select*fromjj_onewhereid

统计信息
———————————————————-
0recursivecalls
6consistentgets
0physicalreads
493bytessentviaSQL*Nettoclient
372bytesreceivedviaSQL*Netfromclient
2SQL*Netroundtripsto/fromclient
2rowsprocessed

在抓取行数小于15的情况下,逻辑读始终为6。

步7:查询16行以上:
sid=11pid=12>select*fromjj_onewhereid

已选择16行。

统计信息
———————————————————-
0recursivecalls
7consistentgets
0physicalreads
699bytessentviaSQL*Nettoclient
383bytesreceivedviaSQL*Netfromclient
3SQL*Netroundtripsto/fromclient
16rowsprocessed

逻辑读已经变成7次。

注意,在10G中,对块读的算法有改进。以同样的谓词条件,访问同样的行时,第一次访问时的逻辑读要比以后再行访问时多的多。因此,在10G中,同样的命令,多执行几次,这样看到的结果比较全面。

还有一点,访问15行以内时,为什么会有6次逻辑读?不应该是1次吗?这里,我相信Setautottracestat命令本身有一定的原因,如果用下面的静态游标:

sid=10pid=11>altersessionsetevents’10046tracenamecontextforever,level14′;
会话已更改。

declare
typemidistableofjj_one.id%type;
mid1mid;
cursorcisselectidfromjj_onewhereid>=1andid
begin
openc;
fetchcbulkcollectintomid1limit15;
dbms_output.put_line(c%rowcount);
closec;
end;
/

sid=10pid=11>altersessionsetevents’10046tracenamecontextoff’;
会话已更改。

用Tkprof格式化跟踪结果:
E:/oracle/admin/mytwo/udump>tkprofmytwo_ora_756.trcm3.txt

查看M3.txt文件:
callcountcpuelapseddiskquerycurrentrows
———————————————————————–
Parse10.000.000000
Execute10.000.000000
Fetch10.000.0003015
———————————————————————–
total30.000.0003015

逻辑读只有3次。这3次逻辑读,有一次是针对行所在块的,其余两次是针对段头的。

实验完毕

从上面的实验中可以看出,“成批读取”中,批大小的设定,可以影响逻辑读的数量。批大小越大,读相同数量的行,逻辑读就越少。而且服务端和客户端交互的次数也越少,由网络传输的数据也可以减少,下面看一下测试:
批大小为1:
sid=11pid=12>setarraysize1
sid=11pid=12>select*fromjj_one;
已选择100行。
统计信息
———————————————————-
54consistentgets
7206bytessentviaSQL*Nettoclient
911bytesreceivedviaSQL*Netfromclient
51SQL*Netroundtripsto/fromclient
100rowsprocessed
批大小为100:
sid=11pid=12>setarraysize100
sid=11pid=12>select*fromjj_one;
已选择100行。
统计信息
———————————————————-
6consistentgets
1277bytessentviaSQL*Nettoclient
372bytesreceivedviaSQL*Netfromclient
2SQL*Netroundtripsto/fromclient
100rowsprocessed

差别是很明显的,bytessentviaSQL*Nettoclient的数值,相差了6倍左右。

但这并不代表将批大小设置的越高,速度就越快,否则,Oracle直接将它设置为一个最大的值,不就行了,干吗还要让我们去自己调节呢!
行从Buffercache中读出来后,会先缓存在PGA中(具体是在游标的运行时区),然后再传给客户端。如果批大小过大,在PGA、客户端占用的内存也会增大。而且,如果渐歇性的在网络上传输大量数据,对网络也会有一定影响。下面来观察一下批大小对PGA的影响:
在会话11中执行如下过程:
declare
typemidistableoft1.id%type;
mid1mid;
cursorcisselectidfromt1;
begin
openc;
loop
fetchcbulkcollectintomid1limit5000;
exitwhenc%notfound;
endloop;
dbms_output.put_line(c%rowcount);
closec;
end;
/

在另一会话中观察会话11的内存占用情况:
sid=10pid=11>@pga–此脚本下面有说明
输入user的值:11
原值7:andb.sid=&user
新值7:andb.sid=11

PGAUsedPGAAllocPGAMax
——————————
561508779492779492

然后将会话11中过程的批大小改为1:fetchcbulkcollectintomid1limit5000;再试一次

在另一会话观察会话11的PGA占用情况:
sid=10pid=11>@pga
输入user的值:11
原值7:andb.sid=&user
新值7:andb.sid=11

PGAUsedPGAAllocPGAMax
——————————
184388250668250668

批大小为5000时的内存占用,是批大小为1时的3倍左右。另外,测试表一定要大一些,我的测试表是1000000行,否则不容易看到结果。在10G中,可以得到基本相同的结果。

PGA.SQL脚本如下:
–pga_by_process.sql:
SELECT
a.pga_used_mem”PGAUsed”,
a.pga_alloc_mem”PGAAlloc”,
a.pga_max_mem”PGAMax”
FROMv$processa,v$sessionb
wherea.addr=b.paddr
andb.sid=&user

感谢各位的阅读!关于“Oracle逻辑读的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

相关推荐: PostgreSQL浮点数是怎么实现的

这篇文章主要介绍“PostgreSQL浮点数是怎么实现的”,在日常操作中,相信很多人在PostgreSQL浮点数是怎么实现的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL浮点数是怎么实现的”的疑惑有所帮助!接…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 01/14 18:18
Next 01/14 18:18