10.2.0.4.0里请慎用压缩表(续)

| No Comments

我在 "10.2.0.4.0里请慎用压缩表"这篇文章里提到了oracle关于压缩表的一个bug----Bug 7123643 UPDATE TO A COLUMN IN A COMPRESSED TABLE RESULTS IN DATA LOSS

 

我在那篇文章里提到说----"10.2.0.4.0上请慎用压缩表,很有可能会丢数据的"。这个观点本质上来源于MOS上对上述bug的描述,但这种说法是不确切的,或者说至少是不准确的!我当时对压缩块的格式还不熟悉,现在已经不一样了。

 

我们来看看真相是什么,首先让我们来重现上述问题。

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 SDAFCRSDAFAR的情况下,它们的值均为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 SDAFCRSDAFAR,还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: 2c 00 32 a0 0b 29 1b ff 2b ff 48 ff ff ff ff 50 4e 66 ff ff 54 51 ff 2b ff ff 4e cf 35 37 33 32 34 31 37 cc c3 37 46 30 4f 67 48 65 cd c4 03 04 0b 2e ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

 

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秒,而压缩表则用了112,为什么会有这么大的差异,我下一篇文章会专门阐述这个问题。

 

不一致已经产生,也就是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 2f 31 47

col 202: [ 5]  c4 15 09 0d 20

col 203: [ 6]  44 4c 43 44 4c 43

col 204: [ 5]  c4 03 04 0b 2e

bindmp: 2c 00 cd 00 cb 39 39 39 cd 30 30 30 30 31 cb 42 53 50 c9 50 ff c9 42 c9 49 cc 54 4b 54 54 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff cd c4 15 0b 02 20 ff ff ff ff ff ff cc 74 65 73 74 ff ff c9 4d c9 4e ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff cd c4 15 0b 07 1e d0 c7 15 0b 07 1e 0c 07 10 ff ff ff ff ff ff ff ff ff ff ca c1 02 ff ff cc c3 15 0a 09 ff ff ff ff ff ff c9 59 cd c4 15 0b 08 16 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff c9 4e cd c4 15 09 0d 20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff c9 59 ca c1 03 c9 59 ff ff ff ff ff cc 47 44 53 4c cb 45 55 52 ca 54 55 ff ca c1 03 ff cd c4 15 09 0d 20 ff ff ff ff cc 46 46 56 56 cb 31 37 32 cf 35 37 33 32 34 31 36 ff ff d9 42 44 55 42 32 30 30 38 31 32 33 31 45 55 52 30 31 d0 c7 15 0a 09 0a 0b 09 33 ff ca c1 03 ff ff cb 31 37 32 cf 35 37 33 32 34 31 37 cc c3 37 46 30 d0 33 36 32 30 33 30 35 33 d1 56 38 31 53 54 49 2f 31 47 cd c4 15 09 0d 20 ce 44 4c 43 44 4c 43 cd c4 03 04 0b 2e

可以看到现在这一行已经被oracle解压缩了(注意到行头的第4byte已经由0xa0变成了0x00),这里列序号只到204就终止了,这是正常的,因为对于非压缩块而言,如果从某一列之后的值全为null,则oracle并不会在行里存储这些null值,就好像没有这些列一样。

也就是说SDAFCRSDAFAR的值确实是null

 

那么为什么oracle会显示SDAFCR的值是AED

tab 1, row 20, @0x10d0

tl: 9 fb: --H----- lb: 0x0  cc: 0

nrid:  0x02c2cda6.5

bindmp: 20 00 00 02 c2 cd a6 00 05

 

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,压缩块内的数据其实并没有丢失,只是oracleselect的时候出了问题。我这里测试的结果是对单列select的时候是没问题的,但是如果是select *,则结果就不对了。

数据块里的checksum值可能是0吗

| 2 Comments

今天有朋友留言说他的一个块的checksum值是0,问我是为啥。

我开始本以为他说的这个块是空块,但从他随后的留言可以看出,这个块并不是空块。

 

其实在oracle里一个块的checksum值完全有可能是0,我们来看一个实例:

BBED> set file 4

        FILE#           4

 

BBED> set block 32

        BLOCK#          32

 

可以看到现在这个块的checksum值是0x9339

BBED> dump

 File: /dras20/testdb/drsys01.dbf (4)

 Block: 32               Offsets:    0 to  511           Dba:0x01000020

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

 06020000 01000020 0002052e 00000204 93390000 0106001d 0000672f 0002052e

 00008aa8 00023200 01000019 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 ffff000e 1f981f8a 1f8a0000 00000000 0006000d 000000d1

 ......省略显示部分内容

 1b011b12 1b231b34 1b451b56 1b671b78 1b891b9a 1bab1bbc 1bcd1bde 1bef1c00

 

 <32 bytes per line>

 

这个块是一个完好的块:

BBED> verify

DBVERIFY - Verification starting

FILE = /dras20/testdb/drsys01.dbf

BLOCK = 32

 

 

DBVERIFY - Verification complete

 

Total Blocks Examined         : 1

Total Blocks Processed (Data) : 1

Total Blocks Failing   (Data) : 0

Total Blocks Processed (Index): 0

Total Blocks Failing   (Index): 0

Total Blocks Empty            : 0

Total Blocks Marked Corrupt   : 0

Total Blocks Influx           : 0

 

现在我们来让其checksum值变为0

BBED> set offset 64

        OFFSET          64

 

BBED> dump

 File: /dras20/testdb/drsys01.dbf (4)

 Block: 32               Offsets:   64 to  575           Dba:0x01000020

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

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 ffff000e 1f981f8a 1f8a0000 00000000 0006000d 000000d1

 00806849 002f5600 00020000 00000000 0e000000 00409018 004003e1 00018503

  ......省略显示部分内容

 1d1f1d30 1d401d51 1d621d73 1d841d95 1da61db7 1dc81dd9 1dea1dfb 1e0c1e1d

 

 <32 bytes per line>

 

BBED> modify /x 9339 

Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y

 File: /dras20/testdb/drsys01.dbf (4)

 Block: 32               Offsets:   64 to  575           Dba:0x01000020

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

 93390000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 ffff000e 1f981f8a 1f8a0000 00000000 0006000d 000000d1

 00806849 002f5600 00020000 00000000 0e000000 00409018 004003e1 00018503

 ......省略显示部分内容

 1d1f1d30 1d401d51 1d621d73 1d841d95 1da61db7 1dc81dd9 1dea1dfb 1e0c1e1d

 

 <32 bytes per line>

 

注意到oracle这里已经提示我新算出来的checksum值就是0了:

BBED> sum apply

Check value for File 4, Block 32:

current = 0x0000, required = 0x0000

 

可以看到现在这个块的checksum值就是0x0000

BBED> dump

 File: /dras20/testdb/drsys01.dbf (4)

 Block: 32               Offsets:    0 to  511           Dba:0x01000020

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

 06020000 01000020 0002052e 00000204 00000000 0106001d 0000672f 0002052e

 00008aa8 00023200 01000019 00000000 00000000 00000000 00000000 00000000

 93390000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

......省略显示部分内容

 1b011b12 1b231b34 1b451b56 1b671b78 1b891b9a 1bab1bbc 1bcd1bde 1bef1c00

 

 <32 bytes per line>

 

修改后的这个块也是一个完好的块:

BBED> verify

DBVERIFY - Verification starting

FILE = /dras20/testdb/drsys01.dbf

BLOCK = 32

 

 

DBVERIFY - Verification complete

 

Total Blocks Examined         : 1

Total Blocks Processed (Data) : 1

Total Blocks Failing   (Data) : 0

Total Blocks Processed (Index): 0

Total Blocks Failing   (Index): 0

Total Blocks Empty            : 0

Total Blocks Marked Corrupt   : 0

Total Blocks Influx           : 0

 

这种现象其实本质是由oraclechecksum值算法决定的。

Recent Comments

  • watch movies online: Brilliant, just fabulous! Love to see stories that make you read more
  • cui hua: 我这里写的有问题,我的原意是想说“oracle首先会去hash chain中找,看看要找的block是否已经缓存在buffer cache中,找到了就直接用”。 read more
  • xxd: 请教下,文中有一个地方有个疑问"找不到就再去LRU AUXILIARY LIST中找free block" 然而在扫描LRU List这个过程中有个阀值:Max percentage of LRU list read more
  • cui hua: checksum值的作用在于DBWn常规写或user process直接路径写的时候,oracle会根据一个checksum算法,计算数据块的checksum值,然后写入数据块的offset为16-17的位置,并且此后oracle在读取块时,会再次检验这个块上记录的checksum值和oracle此时现算出来的这个块的checksum值是否相等(跟checksum值是否为0没有任何关系),主要为了是防止IO硬件和IO子系统的错误。这里optional的含义是指你可以通过设置参数db_block_checksum的值来控制是否对非system表空间下的块执行写及校验checksum值的动作。 read more
  • xxd: 十分感谢你的解释,我随后参考了些资料,发现这个Checksum value的解释为:ChkVal: Optional check value for the block,所以说他是个"可选的"值,那么在什么情况下他是可选择的?我理解的checksum是oracle通过checksum value 用来得知由底层磁盘是否损坏,那么这个value如果为0,岂不是oracle会把它认为是个坏块儿?谢谢 read more
  • cui hua: 晓东,这种现象是正常的。你看看我这篇文章—— http://dbsnake.com/2010/08/checksum-value-zero.html read more
  • xxd: 都校验过了没有什么错误,如何把块发给你? read more
  • cui hua: 那你用dbv校验一下这个块或者直接在BBED里执行verify命令,看看是否报checksum值计算错误?如果dbv不报错,那就说明这个块的checksum值有可能就是0x00。你可以把这个块发给我,我来算一下——我知道oracle中计算块的checksum值的算法。 read more
  • xxd: 这个不是个空块, BBED> dump File: /u02/oradata/test01.dbf (8) Block: 13 Offsets: 0 read more
  • cui hua: 因为你这个块是一个空块!你注意看你这个块的第一个byte,是否是0x00? read more

Find recent content on the main index or look in the archives to find all content.