什么是Oracle Past Image(pi)
By Todd Bao on 二月 17, 2011
Past Image是一种RAC环境中脏缓冲块的状态,是集群中不同实例对同一个数据缓冲块写而又写后的间接结果。简而言之,Past Image是一种特殊的脏数据块,它保留了前一次更改后的样子。浪漫些,它是一个残像。针对一个特定的数据块,每一个实例最多只能有一个残像(pi)。
实例间争夺、修改热块很容易观察到Past Image,即残像。
当前环境是这样的:HR.EMPLOYEES中的100号员工和101号员工都在5号文件的88号数据块中。从此称此数据块为球,让两个实例争夺这个球。
# 观测1: 球不在任何节点上。
SYS@RAC1//scripts> select inst_id,status from gv$bh where file#=5 and block#=88;
no rows selected
# 节点1要球。(可怜的Steve King, 你本来有24000薪水的。)
SYS@RAC1//scripts> update hr.employees set salary=1 where employee_id=100;
1 row updated.
# 观测2: 球在节点1上。xcur表示写调用的当前数据缓冲,即排他当前数据块。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + xcur
1 row selected.
# 节点2要球。
SYS@RAC2//scripts> update hr.employees set salary=2 where employee_id=101;
1 row updated.
# 观测3: 球在节点2上,残像在节点1上。pi表示Past Image,也就是残像。它保留了数据块前一次更改后的样子。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
2 + Y + xcur
2 rows selected.
# 节点1要球。
SYS@RAC1//scripts> update hr.employees set salary=3 where employee_id=100;
1 row updated.
# 观测4: 球在节点1上,残像在节点2和节点1上都存在。节点2上的残像比节点1上的残像更新。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
1 + Y + xcur
2 + Y + pi
3 rows selected.
# 节点2又要球。
SYS@RAC2//scripts> update hr.employees set salary=4 where employee_id=101;
1 row updated.
# 观测5: 球在节点2上,很不巧这时候发生了增量检查点,DBWR醒了,想到要工作了,残像(pi)变成了陈旧的一致性读缓存块(cr)。它们完全可以被覆盖。坑爹的我辛苦产生的残像都没了。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + N + cr
1 + N + cr
2 + Y + xcur
3 rows selected.
# 重来。节点1要球。
SYS@RAC1//scripts> update hr.employees set salary=5 where employee_id=100;
1 row updated.
# 观测6: 球在节点1上,残像在节点2上。陈旧的一致性读缓存块不用理会,它们随时可以消失。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + xcur
1 + N + cr
1 + N + cr
2 + Y + pi
4 rows selected.
# 节点2要球。
SYS@RAC2//scripts> update hr.employees set salary=6 where employee_id=101;
1 row updated.
# 观测7: 球在节点2上,残像在节点1和2上。节点1上的残像比节点2上的残像更新。回顾一下观测4,很相似。两节点上的残像都出现了。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
2 + Y + pi
2 + Y + xcur
3 rows selected.
# 节点1要球。
SYS@RAC1//scripts> update hr.employees set salary=7 where employee_id=100;
1 row updated.
# 观测8: 球在节点1上,残像在节点2和1上。节点2上的残像比节点1上的残像更新。原来在节点2上的残像变成了陈旧的一致性读缓存块。没有破坏每一个实例最多只能有一个残像(针对同一个数据块)的规则。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
1 + Y + xcur
2 + Y + pi
2 + N + cr
4 rows selected.
不考虑任何检查点的话, 当xcur块移动到另一个节点时:原来节点上的xcur块转变成pi块、原来的pi块(如果有的话)转变为cr块,结果是cr块越来越多,pi则最多和节点数一样多。
接下来让两个节点进行一次弹珠球大战:同时在两个节点上执行匿名块A和B。
A:
SYS@RAC1//scripts> run
1 begin
2 for i in 1..100000 loop
3 update hr.employees set salary=i where employee_id=100;
4 end loop;
5* end;
B:
SYS@RAC2//scripts> run
1 begin
2 for i in 1..100000 loop
3 update hr.employees set salary=i where employee_id=101;
4 end loop;
5* end;
等到它们执行完毕后,看一下5号文件88号数据块在buffer cache中占了几个位置:
SYS@RAC2//scripts> select count(*) from gv$bh where file#=5 and block#=88;
COUNT(*)
----------
412
1 row selected.
其中409个是一致性读块缓冲(cr):
SYS@RAC2//scripts> select count(*) from gv$bh where file#=5 and block#=88 where status='cr';
COUNT(*)
----------
409
1 row selected.
1个排他当前块缓冲(xcur):
SYS@RAC2//scripts> select count(*) from gv$bh where file#=5 and block#=88 where status='xcur';
COUNT(*)
----------
1
1 row selected.
还有...2个我们的主角--残像缓冲(pi)。分别在两个节点上。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88 and status='pi';
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
2 + Y + pi
2 rows selected.
某些时候,当你在RAC环境中发现大量的一致性读缓冲(cr)时,可能你看到的是实例间争夺热块的搏斗痕迹。这是一个xcur到pi再到cr的过程。
那么pi有什么作用? 至少有两个作用。
一,需要时节点可以从本地的pi块制造cr块,避免从其他节点请求cr块。
二,当拥有xcur块的实例崩溃后,pi块重新转变为xcur块,提高了实例恢复的速度。
实例间争夺、修改热块很容易观察到Past Image,即残像。
当前环境是这样的:HR.EMPLOYEES中的100号员工和101号员工都在5号文件的88号数据块中。从此称此数据块为球,让两个实例争夺这个球。
# 观测1: 球不在任何节点上。
SYS@RAC1//scripts> select inst_id,status from gv$bh where file#=5 and block#=88;
no rows selected
# 节点1要球。(可怜的Steve King, 你本来有24000薪水的。)
SYS@RAC1//scripts> update hr.employees set salary=1 where employee_id=100;
1 row updated.
# 观测2: 球在节点1上。xcur表示写调用的当前数据缓冲,即排他当前数据块。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + xcur
1 row selected.
# 节点2要球。
SYS@RAC2//scripts> update hr.employees set salary=2 where employee_id=101;
1 row updated.
# 观测3: 球在节点2上,残像在节点1上。pi表示Past Image,也就是残像。它保留了数据块前一次更改后的样子。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
2 + Y + xcur
2 rows selected.
# 节点1要球。
SYS@RAC1//scripts> update hr.employees set salary=3 where employee_id=100;
1 row updated.
# 观测4: 球在节点1上,残像在节点2和节点1上都存在。节点2上的残像比节点1上的残像更新。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
1 + Y + xcur
2 + Y + pi
3 rows selected.
# 节点2又要球。
SYS@RAC2//scripts> update hr.employees set salary=4 where employee_id=101;
1 row updated.
# 观测5: 球在节点2上,很不巧这时候发生了增量检查点,DBWR醒了,想到要工作了,残像(pi)变成了陈旧的一致性读缓存块(cr)。它们完全可以被覆盖。坑爹的我辛苦产生的残像都没了。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + N + cr
1 + N + cr
2 + Y + xcur
3 rows selected.
# 重来。节点1要球。
SYS@RAC1//scripts> update hr.employees set salary=5 where employee_id=100;
1 row updated.
# 观测6: 球在节点1上,残像在节点2上。陈旧的一致性读缓存块不用理会,它们随时可以消失。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + xcur
1 + N + cr
1 + N + cr
2 + Y + pi
4 rows selected.
# 节点2要球。
SYS@RAC2//scripts> update hr.employees set salary=6 where employee_id=101;
1 row updated.
# 观测7: 球在节点2上,残像在节点1和2上。节点1上的残像比节点2上的残像更新。回顾一下观测4,很相似。两节点上的残像都出现了。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
2 + Y + pi
2 + Y + xcur
3 rows selected.
# 节点1要球。
SYS@RAC1//scripts> update hr.employees set salary=7 where employee_id=100;
1 row updated.
# 观测8: 球在节点1上,残像在节点2和1上。节点2上的残像比节点1上的残像更新。原来在节点2上的残像变成了陈旧的一致性读缓存块。没有破坏每一个实例最多只能有一个残像(针对同一个数据块)的规则。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88;
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
1 + Y + xcur
2 + Y + pi
2 + N + cr
4 rows selected.
不考虑任何检查点的话, 当xcur块移动到另一个节点时:原来节点上的xcur块转变成pi块、原来的pi块(如果有的话)转变为cr块,结果是cr块越来越多,pi则最多和节点数一样多。
接下来让两个节点进行一次弹珠球大战:同时在两个节点上执行匿名块A和B。
A:
SYS@RAC1//scripts> run
1 begin
2 for i in 1..100000 loop
3 update hr.employees set salary=i where employee_id=100;
4 end loop;
5* end;
B:
SYS@RAC2//scripts> run
1 begin
2 for i in 1..100000 loop
3 update hr.employees set salary=i where employee_id=101;
4 end loop;
5* end;
等到它们执行完毕后,看一下5号文件88号数据块在buffer cache中占了几个位置:
SYS@RAC2//scripts> select count(*) from gv$bh where file#=5 and block#=88;
COUNT(*)
----------
412
1 row selected.
其中409个是一致性读块缓冲(cr):
SYS@RAC2//scripts> select count(*) from gv$bh where file#=5 and block#=88 where status='cr';
COUNT(*)
----------
409
1 row selected.
1个排他当前块缓冲(xcur):
SYS@RAC2//scripts> select count(*) from gv$bh where file#=5 and block#=88 where status='xcur';
COUNT(*)
----------
1
1 row selected.
还有...2个我们的主角--残像缓冲(pi)。分别在两个节点上。
SYS@RAC1//scripts> select inst_id,dirty,status from gv$bh where file#=5 and block#=88 and status='pi';
INST_ID + D + STATUS
---------- + - + -------
1 + Y + pi
2 + Y + pi
2 rows selected.
某些时候,当你在RAC环境中发现大量的一致性读缓冲(cr)时,可能你看到的是实例间争夺热块的搏斗痕迹。这是一个xcur到pi再到cr的过程。
那么pi有什么作用? 至少有两个作用。
一,需要时节点可以从本地的pi块制造cr块,避免从其他节点请求cr块。
二,当拥有xcur块的实例崩溃后,pi块重新转变为xcur块,提高了实例恢复的速度。