前一篇我写了位图索引的阻塞与死锁分析,但是,那是在oracle 10g上做的,其实,Oracle 9i与oracle 10g的位图索引是有很大差别的。oracle 10g对比oracle 9i,在位图索引上做了非常多的改动,详细见
9i的位图索引内部研究:
http://www.itpub.net/showthread.php?threadid=114023
10g的位图索引内部研究:
http://www.itpub.net/showthread.php?threadid=743939
我这里不想讨论这些内部结构,只是想通过2个实验,来看看位图索引的阻塞范围。
我先拿9i做实验:
- Piner@Ora9iR2> create table test(id int,flag int);
- Table created.
- Piner@Ora9iR2> create bitmap index ind_test on test(flag);
- Index created.
我们看看使用空间,初始化默认就是2个块,其中有一个是段头。
- Piner@Ora9iR2> exec show_space('IND_TEST','INDEX');
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................6
- Unused Bytes............................49152
- Last Used Ext FileId....................1
- Last Used Ext BlockId...................50121
- Last Used Block.........................2
- PL/SQL procedure successfully completed.
我们插入1000条数据,其中,flag字段为0与1,因为任何数与2 mod之后,都是0或者是1。
- Piner@Ora9iR2> begin
- 12:39:56 2 for i in 1 .. 1000 loop
- 12:39:56 3 insert into test values(i,mod(i,2));
- 12:39:56 4 end loop;
- 12:39:56 5 commit;
- 12:39:56 6 end;
- 12:39:57 7 /
- PL/SQL procedure successfully completed.
再检查使用情况
- Piner@Ora9iR2> exec show_space('IND_TEST','INDEX');
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................2
- Unused Bytes............................16384
- Last Used Ext FileId....................1
- Last Used Ext BlockId...................50121
- Last Used Block.........................6
- PL/SQL procedure successfully completed.
发现,1000条数据,就使用了6个块(包括一个段头),也就是新增了4个块。
再看看阻塞情况,注意,id=1与id=2的flag值肯定不一样。
会话1
- Piner@Ora9iR2> update test set flag=2 where id=1;
- 1 row updated.
会话2
- Piner@Ora9iR2> update test set flag=3 where id=2;
- 阻塞。。。
可以看到这里阻塞了,也就是说,Oracle 9i的阻塞不考虑原来的值与新值,这个与下面测试的oracle 10g不一样。
我们另外再考虑一组测试,注意,这个测试中,如果原来是0,则更新成1,如果原来是1,则更新成0
会话1
- Piner@Ora9iR2> update test set flag=decode(flag,1,0,1) where id=1;
- 1 row updated.
会话2
- Piner@Ora9iR2> update test set flag=decode(flag,1,0,1) where id=8;
- 阻塞
会话3
- Piner@Ora9iR2> update test set flag=decode(flag,1,0,1) where id=9;
- 1 row updated.
通过以上可以发现,9i的阻塞是阻塞一个范围段,如以上就是8条记录,不管更新的值怎么样,就是把这范围段给阻塞了,这个也是与以下10g不同的一个地方。也就是说,在oracle 9i中,8条记录这个范围段以外的记录不被阻塞,我们通过如下的实验也可以发现只阻塞8条记录。
- Piner@Ora9iR2>set serveroutput on size 200000
- Piner@Ora9iR2>begin
- 2 for i in 9..1000 loop
- 3 update test set flag=decode(flag,1,0,1) where id=i;
- 4 dbms_output.put_line(i||':'||sql%rowcount);
- 5 end loop;
- 6 end;
- 7 /
- 结果为:
- 9:1
- 10:1
- ...
- 999:1
- 1000:1
可以看到,除了前8条记录以外的所有记录,都更新成功了。
那么,在oracle 10g中,有些什么样的变化呢?其实,在我的上一篇文章中大致提到了,我们再看一下。我们同样创建一个表与位图索引。
- Piner@10gR2>create table test(id int,flag int);
- Table created.
- Piner@10gR2>create bitmap index ind_test on test(flag);
- Index created.
- Piner@10gR2>exec show_space('IND_TEST','INDEX');
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................6
- Unused Bytes............................49152
- Last Used Ext FileId....................1
- Last Used Ext BlockId...................28217
- Last Used Block.........................2
- PL/SQL procedure successfully completed.
以上的结果与9i相同,都是初始化2个块,其中一个是段头块。我们插入数据看看
- Piner@10gR2>begin
- 2 for i in 1 .. 20000 loop
- 3 insert into test values(i,mod(i,2));
- 4 end loop;
- 5 commit;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- Piner@10gR2>exec show_space('IND_TEST','INDEX');
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................6
- Unused Bytes............................49152
- Last Used Ext FileId....................1
- Last Used Ext BlockId...................28217
- Last Used Block.........................2
- PL/SQL procedure successfully completed.
以上看到第一个差别了,9i只插入1000条数据,就使用了6个块,但是,10g现在插入了2w条数据了,但是还是2个块,可见10g的位图索引具有比较好的压缩功能。
我们再插入10000条数据。
- Piner@10gR2>begin
- 2 for i in 20001 .. 30000 loop
- 3 insert into test values(i,mod(i,2));
- 4 end loop;
- 5 commit;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- Piner@10gR2>exec show_space('IND_TEST','INDEX');
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................4
- Unused Bytes............................32768
- Last Used Ext FileId....................1
- Last Used Ext BlockId...................28217
- Last Used Block.........................4
- PL/SQL procedure successfully completed.
这次,才终于新增加了2个leaf block块,现在有4个块了。
那么,我们看看阻塞情况:
会话1
- Piner@10gR2>update test set flag=decode(flag,1,0,1) where id=1;
- 1 row updated.
会话2
- Piner@10gR2>update test set flag=decode(flag,1,0,1) where id=20000;
- 阻塞
会话3
- Piner@10gR2>update test set flag=decode(flag,1,0,1) where id=30000;
- 1 row updated.
可以看到,10g的阻塞范围很大了,id=1阻塞了id=20000的记录,但是没有阻塞id=30000的记录,这里说明了,10g的阻塞是以索引块为单位的,阻塞了整个索引块中的记录,因为在插入20000条记录的时候还没有扩展新的索引块,可以说明id=1与id=20000是在一个索引块中的,而id=30000的时候,扩展了索引块,可以表示id=30000是在另外一个索引块中。我们进一步分析:
会话1
- Piner@10gR2>update test set flag=2 where id=1;
- 1 row updated.
会话2
- Piner@10gR2>update test set flag=3 where id=2;
- 1 row updated.
这里没有阻塞,这里也不同于9i了,说明10g的阻塞是与值有关系的,也就是10g的阻塞是看旧值与新值的,只阻塞同一个块中的旧值与新值,而不阻塞与新值以及旧值无关的值。
最后,总结一下,9i的阻塞范围是分段的,如8条记录,不管值如何,全部阻塞。而10g具有良好的位图索引的压缩功能,但是阻塞同一个索引块中的旧值与新值(这个范围可能比9i要大很多)。这些特性,怀疑与10g的压缩功能有关系。
上一篇: « 公司outing,到达海边的下榻酒店
下一篇: 弄清楚你的业务类型——OLTP or OLAP »
- 发表评论


