我在 "
我在那篇文章里提到说----"
我们来看看真相是什么,首先让我们来重现上述问题。
SQL> create table t1 as select * from saldat where rownum<120001;
Table created
SQL> select count(*) from t1;
COUNT(*)
----------
120000
SQL> create table t2 compress as select * from t1;
Table created
SQL> select count(*) from t2;
COUNT(*)
----------
120000
SQL> select count(*) from (select * from t1 minus select * from t2);
COUNT(*)
----------
0
我定位到t2表中的一行记录,注意到此时我在只select SDAFCR和SDAFAR的情况下,它们的值均为null:
SQL> select sdafcr,sdafar,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from t2 t where sdaprf='999' and sdafrm='172' and sdatkt='5732417';
SDAFCR SDAFAR LOCATION
------ ----------------- --------------------------------------------------------------------------------
9_186026
当我在除了select SDAFCR和SDAFAR,还select *的情况下,它们的值还是维持null不变:
SQL> select sdafcr,sdafar,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location,t.* from t2 t where sdaprf='999' and sdafrm='172' and sdatkt='5732417';
SDAFCR SDAFAR LOCATION
SDAPRF SDAFRM SDATKT SDACHK SDASEQ SDABTH
......省略显示部分内容 SDAUID SDAUDT SDAPRS SDAVOD SDAADF SDAPER SDABTN SDAGPN SDA
------ ----------------- -------------------------------------------------------------------------------- ------ ------
9_186026 999 172 5732417 2 546947 BDUB20081231EUR01 00001 BSP ......省略显示部分内容 20090809100850 M FFVV N
我们现在看一下9_186026这个块中的上述行:
tab 1, row 19, @0xbcf
tl: 70 fb: --H-FL-- lb: 0x0 cc: 225
col 0: [ 3] 39 39 39
......省略显示部分内容
col 197: [ 3] 31 37 32
col 198: [ 7] 35 37 33 32 34 31 37
......省略显示部分内容
col 205: *NULL*
col 206: *NULL*
col 207: *NULL*
col 208: *NULL*
col 209: *NULL*
col 210: *NULL*
col 211: *NULL*
col 212: *NULL*
col 213: *NULL*
col 214: *NULL*
col 215: *NULL*
col 216: *NULL*
col 217: *NULL*
col 218: *NULL*
col 219: *NULL*
col 220: *NULL*
col 221: *NULL*
col 222: *NULL*
col 223: *NULL*
col 224: *NULL*
bindmp:
SQL> desc t2;
Name Type Nullable Default Comments
------ ------------- -------- ------- --------
SDAPRF VARCHAR2(4) ――第0列
SDAFRM VARCHAR2(3) ――第1列
SDATKT VARCHAR2(8) ――第2列
SDACHK NUMBER(1) Y
......省略显示部分内容
SDAFCC VARCHAR2(400) Y
SDAFCR VARCHAR2(3) Y ----第51列
SDAFAR NUMBER(15,4) Y ――第52列
SDAEFA NUMBER(15,4) Y
......省略显示部分内容
SDACAE VARCHAR2(11) Y
而上述块中的perm_9ir2数组为:
perm_9ir2[225]={ 0 197 198 194 199 191 1 2 150 3 175 4 200 5 6 7 176 205 8 195 206 9 152 153 196 207 193 208 190 209 10 11 154 210 155 156 211 12 212 157 213 214 215 13 158 216 159 14 160 183 217 218 219 220 15 16 17 18 19 20 21 161 22 23 24 25 178 221 26
182 162 180 27 163 28 29 30 31 32 33 34 35 222 36 201 164 223 165 184 37 38 39 40 185 166 41 42 167 187 188 179 168 43 44 45 46 202 181 151 47 48 49 50 169 51 52 53 54 55 192 56 57 58 186 59 60 61 62 189 170 63 171 172 64 65 224 66 67 68 69 70 71 72 73 74
75 76 77 78 79 80 81 82 203 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 177 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 173 134 135 136 137 138 174 139 140 141
142 143 204 144 145 146 147 148 149 }
从结果里我们可以看出,上述行至少有0xa0列被压缩了。
现在我们来执行产生不一致的修改操作:
18:37:31 SQL> update t1 set sdapgc=0.5;
120000 rows updated
18:37:42 SQL> update t2 set sdapgc=0.5;
120000 rows updated
18:38:54 SQL> commit;
Commit complete
从上述结果里可以看出,同样都是更新12万条记录,非压缩表只用了11秒,而压缩表则用了1分12秒,为什么会有这么大的差异,我下一篇文章会专门阐述这个问题。
不一致已经产生,也就是MOS上提到的所谓的丢了数据:
SQL> select count(*) from (select * from t1 minus select * from t2);
COUNT(*)
----------
917
我们之前看的那条记录,即sdaprf='999' and sdafrm='172' and sdatkt='5732417'的那条记录,刚好是处于不一致的区域:
SQL> select sdaprf,sdafrm,sdatkt from (select * from t1 minus select * from t2) where rownum<2;
SDAPRF SDAFRM SDATKT
------ ------ --------
999 172 5732417
注意仔细看我如下的查询:
SQL> select sdafcr,sdafar,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from t2 t where sdaprf='999' and sdafrm='172' and sdatkt='5732417';
SDAFCR SDAFAR LOCATION
------ ----------------- --------------------------------------------------------------------------------
9_186026
SQL> select sdafcr,sdafar,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location,t.* from t2 t where sdaprf='999' and sdafrm='172' and sdatkt='5732417';
SDAFCR SDAFAR LOCATION
SDAPRF SDAFRM SDATKT SDACHK SDASEQ SDABTH
......省略显示部分内容 SDAUID SDAUDT SDAPRS SDAVOD SDAADF SDAPER SDABTN SDAGPN SDA
------ ----------------- -------------------------------------------------------------------------------- ------ ------
AED 2630.0000 9_186026
999 172 5732417 2 546947 BDUB20081231EUR01 00001 BSP ......省略显示部分内容 20090809100850 M FFVV N
从结果我们可以看到,现在已经出现了自相矛盾,不合情理的不一致。
我们的问题是:
SDAFCR的值到底是null还是AED?
SDAFAR的值到底是null还是2630.0000?
我们来看一下修改后的块9_186026:
现在的perm_9ir2数组依然为:
perm_9ir2[225]={ 0 197 198 194 199 191 1 2 150 3 175 4 200 5 6 7 176 205 8 195 206 9 152 153 196 207 193 208 190 209 10 11 154 210 155 156 211 12 212 157 213 214 215 13 158 216 159 14 160 183 217 218 219 220 15 16 17 18 19 20 21 161 22 23 24 25 178 221 26
182 162 180 27 163 28 29 30 31 32 33 34 35 222 36 201 164 223 165 184 37 38 39 40 185 166 41 42 167 187 188 179 168 43 44 45 46 202 181 151 47 48 49 50 169 51 52 53 54 55 192 56 57 58 186 59 60 61 62 189 170 63 171 172 64 65 224 66 67 68 69 70 71 72 73 74
75 76 77 78 79 80 81 82 203 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 177 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 173 134 135 136 137 138 174 139 140 141
142 143 204 144 145 146 147 148 149 }
修改后的那一行现在的内容为:
tab 1, row 19, @0x10d9
tl: 377 fb: --H-FL-- lb: 0x0 cc: 205
col 0: [ 3] 39 39 39
......省略显示部分内容
col 197: [ 3] 31 37 32
col 198: [ 7] 35 37 33 32 34 31 37
col 199: [ 4] c3 37 46 30
col 200: [ 8] 33 36 32 30 33 30 35 33
col 201: [ 9] 56 38 31 53 54 49
col 202: [ 5] c4 15 09 0d 20
col 203: [ 6] 44
col 204: [ 5] c4 03 04 0b 2e
bindmp:
可以看到现在这一行已经被oracle解压缩了(注意到行头的第4个byte已经由0xa0变成了0x00),这里列序号只到204就终止了,这是正常的,因为对于非压缩块而言,如果从某一列之后的值全为null,则oracle并不会在行里存储这些null值,就好像没有这些列一样。
也就是说SDAFCR、SDAFAR的值确实是null。
那么为什么oracle会显示SDAFCR的值是AED?
tab 1, row 20, @0x10d0
tl: 9 fb: --H----- lb: 0x0 cc: 0
nrid: 0x
bindmp: 20 00 00
tab 1, row 21, @0xe98
tl: 568 fb: --H-FL-- lb: 0x0 cc: 225
col 0: [ 3] 39 39 39
col 1: [ 5] 30 30 30 30 31
......省略显示部分内容
col 176: [ 3] 41 45 44
col 177: [ 2] 54 55
col 178: [ 2] 43 41
本应该是读第19行,但是oracle这里似乎读到第21行去了。
所以我们的结论就是:
对于上述bug,压缩块内的数据其实并没有丢失,只是oracle在select的时候出了问题。我这里测试的结果是对单列select的时候是没问题的,但是如果是select *,则结果就不对了。
Recent Comments