oracle逻辑读徒增,ORACLE 之物理读和逻辑读、DB Block Gets和consistent gets

一、.物理读(physical read)

当数据块第一次读取到,就会缓存到buffer cache 中,而第二次读取和修改该数据块时就在内存buffer cache 了 以下是例子:

1)、第一次读取:

SQL> set autotrace traceonly

SQL> select * from test;

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=

thread-1711734-1-1.html

1 0 TABLE ACCESS (FULL) OF 'TEST' (Cost=2 Card=4 Bytes=

thread-1711734-1-1.html

Statistics

----------------------------------------------------------

175 recursive calls

0 db block gets

24 consistent gets

9 physical reads --9个物理读

0 redo size

373 bytes sent via SQL*Net to client

503 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

2 sorts (memory)

0 sorts (disk)

1 rows processed

2)、第二次读取

SQL> select * from test;

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=

thread-1711734-1-1.html

1 0 TABLE ACCESS (FULL) OF 'TEST' (Cost=2 Card=4 Bytes=

thread-1711734-1-1.html

Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

7 consistent gets

0 physical reads --没有发生物理读了,直接从buffer cache 中读取了

0 redo size

373 bytes sent via SQL*Net to client

503 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

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

----------------------------------------------------------

0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=4 Bytes=

thread-1711734-1-1.html

1 0 TABLE ACCESS (FULL) OF 'TEST' (Cost=2 Card=4 Bytes=

thread-1711734-1-1.html

Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

7 consistent gets

6 physical reads --又重新发生了物理读

0 redo size

373 bytes sent via SQL*Net to client

503 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

总结:Physical Reads(物理读)就是从磁盘上读取数据块的数量,其产生的主要原因是:

1、 在数据库高速缓存中不存在这些块

2、 全表扫描

3、 磁盘排序

二、逻辑读(buffer read)

逻辑读指的就是从(或者视图从)Buffer Cache中读取数据块。按照访问数据块的模式不同,可以分为即时读(Current Read)和一致性读(Consistent Read)。注意:逻辑IO只有逻辑读,没有逻辑写。

即时读:

即时读即读取数据块当前的最新数据。任何时候在Buffer Cache中都只有一份当前数据块。即时读通常发生在对数据进行修改、删除操作时。这时,进程会给数据加上行级锁,并且标识数据为“脏”数据。

一致性读:

Oracle 是一个多用户系统。当一个会话开始读取数据还未结束读取之前,可能会有其他会话修改它将要读取的数据。如果会话读取到修改后的数据,就会造成数据的不一致。一致性读就是为了保证数据的一致性。在Buffer Cache中的数据块上都会有最后一次修改数据块时的SCN。如果一个事务需要修改数据块中数据,会先在回滚段中保存一份修改前数据和SCN的数据块,然后再更新Buffer Cache中的数据块的数据及其SCN,并标识其为“脏”数据。当其他进程读取数据块时,会先比较数据块上的SCN和自己的SCN。如果数据块上的SCN 小于等于进程本身的SCN,则直接读取数据块上的数据;如果数据块上的SCN大于进程本身的SCN,则会从回滚段中找出修改前的数据块读取数据。通常,普通查询都是一致性读。

总结:

DB Block Gets(当前请求的块数目)

当前模式块意思就是在操作中正好提取的块数目,而不是在一致性读的情况下而产生的块数。查看的是当前被修改过的,例如你A用户修改2行记录,然后修改完后(不管有没有提交,只要还在内存中保持最新)A用户立马select这两条记录,就会产生db block gets.也就是本身用户A的DML。

consistent gets

Consistent Gets(数据请求总数在回滚段Buffer中的数据一致性读所需要的数据块)这里的概念是在处理你这个操作的时候需要在一致性读状态上处理多少个块,这些块产生的主要原因是因为由于在你查询的过程中,由于其他会话对数据块进行操作,而对所要查询的块有了修改,但是由于我们的查询是在这些修改之前调用的,所以需要对回滚段中的数据块的前映像进行查询,以保证数据的一致性。这样就产生了一致性读。 查看的是前镜像。例如A用户修改完后没提交,此时B用户开始查询这两条记录,然后就会从undo里面读取前镜像放到内存。就产生了一致性读。也就是其他用户A进行了DML,B要进行SELECT。查询开始之后,若数据发生了变化,则查询需要去从回滚段中获得变化前的数据,而若数据没有发生变化,则不用去回滚段中读了。不管是否去回滚段中读,在概念上来讲,这种数据获取方式都叫 consistent gets 。

三、一致性读(Consistent Read)产生过程

1、在“读”事务开始时,数据块已经被其他事务修改但未被提交,但在数据块被读取到之前,修改已经被提交:

时间: T1 T2 T3 T4

A事务 Block Updated Commit

C事务 Query begin Read Block(Consistent Read)

1)、A事务更新数据,未提交;

2)、修改过的数据块被cache到了buffer中:

3)、C事务开始query,query时间较长,运行中且未读取到被A事务修改过的数据块:

4)、A事务提交修改,这时,C事务读取到该数据块,对数据块的读取是一致性读(CR),其读取的数据是修改前的数据:

5)、看到UNDO数据被copy到了buffer cache中作为CR buffer存在:

6)、 再次读取就是修改后的数据:

2、“读”事务开始之前,数据块被其他事务修改,当“读”事务读取到该数据块时,修改仍未提交,发生一致性读:

时间: T1 T2 T3 T4

A事务 Block Updated Commit

C事务 Query begin Read Block(Consistent Read)

1)、A事务修改数据、未提交:

2)、C事务读取数据块,发生一致性读

3)、CR块被cache:

以上这两种情况可以视为同一种情况:

当数据块在某个事务中被修改了,所有开始于“修改”事务开始后、提交前的所有会读取到该数据块的“读”事务,在读取到该数据块时都会发生一致性读。

3、“读”事务开始后、在读取数据块之前,数据块被其他事务修改且未提交,当读取到该数据块时仍未提交:

时间: T1 T2 T3 T4

A事务 Block Updated Commit

C事务 Query begin Read Block(Consistent Read)

1)、C事务开始query,query时间较长,运行中且未读取到被即将被A事务修改的数据块:

2)、A事务修改数据块,未提交

3)、C事务访问到了被修改过的数据块,发生一致性读,读取到修改前的数据

4)、CR数据块被cache在buffer中:

5)、 再次读取就是修改后的数据:

4、 在“读”事务开始后,未访问到数据块之前,其他事务中更新了数据块且已提交,当“读”事务读取到该数据块时,也同样发生一致性读

时间: T1 T2 T3 T4

A事务 Block Updated Commit

C事务 Query begin Read Block(Consistent Read)

1)、数据块已经在buffer中,直接copy CR块

2)、C事务开始query,query时间较长,运行中:

3)、A事务更新数据且提交:

4)、C事务查询完成,读取到修改的数据,发生一致性读,读取到修改前的数据

5)、CR块被cache在buffer中:

以上这两种情况都可以被视为发生一致性读的另外一种情况:

在“读”事务开始后,如果有数据块被其他事务修改(无论是否被提交),在读取到被修改的数据块时都发生一致性读。

consistent gets 是oracle在查询开始的时候,所获得的数据必须是在时间点上一致的。假定查询开始的时候所有数据都是已经提交的,查询开始之后,若数据发生了变化,则查询需要去从回滚段中获得变化前的数据,而若数据没有发生变化,则不用去回滚段中读了。不管是否去回滚段中读,在概念上来讲,这种数据获取方式都叫 consistent gets 。 这仅仅表示一种期望,需要获得一致的时间点的数据,为此可能需要去回滚段中获得数据但并不表示一定从回滚段中的到数据

你可以认为oracle为读取准备了两个不同的接口,一个是current_read,它的内容是: read current block;当oracle做读取的时候,如果oracle认为需要一致的读取,就用consistent_read,如果需要当前读取,就用current_read。当然大部分query都产生一致读取,除了偶尔需要读segment header的时候。

四、关于读一致性块是被“独享”的

CR buffer只能被产生该buffer的事务读取,而不能被其它事务“共享”,其依据就是buffer中cr_scn_bas,其记录了产生该buffer的事务的SCN,该值只存在于CR Buffer中。

当多个事务都对某个数据块发生一致性读,每个事务都会在buffer中copy一块CR块:

例子:我8点开始跑一个查询,8点20分访问到一个block(这个访问当然是一致模式的访问),那我要查一下这个Block头信息,

情况一是,如果这个block的上一次改变在8点10分发生,那我就需要去读undo(或者读内存里的一致块),

情况二是,如果这个Block的最后一次改变时7点59分,那我就直接读这个block。即使对情况一,也有不同情况:大致是这样的:

如果block在8点10分被修改了一次,oracle会在内存里建立8点10分一致块a(这个一致块是8点10分之前的版本),

如果block在8点11分被修改了一次,oracle会在内存里建立8点11分一致块b(这个一致块是8点10分的版本),

如果block在8点12分被修改了一次,oracle会在内存里建立8点12分一致块c(这个一致块是8点11分的版本),

如果block在8点13分被修改了一次,oracle会在内存里建立8点13分一致块d(这个一致块是8点12分的版本),

如果block在8点14分被修改了一次,oracle会在内存里建立8点14分一致块e(这个一致块是8点13分的版本),

如果block在8点15分被修改了一次,oracle会在内存里建立8点15分一致块f(这个一致块是8点14分的版本),

如果block在8点16分又被修改了一次,oracle会在内存里建立8点16分一致块g,但是维护太多一致块也是很烦的,所以oracle只保留6个一致块(参数_db_block_max_cr_dba决定了一个数据块能copy的cr块数量(包括脏数据块),该参数默认值为6.),所以这时候8点10分建立的一致块会被冲掉, 现在这个block在内存里的一致块就是b~g. 然后,还是前面8点开始的查询,8点20分访问到这个block的时候,我们需要的是8点10分之前的版本,也就是版本a,在cache里已经没有了,这时不得不读Undo, 否则,如果a还在的话,直接读a就可以了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值