簇表

如果两个表经常按照某个列来做连接查询,则
可以考虑将这两个表相关的行按照这个连接列聚
簇到一个簇中。

簇的优点:

1):两表连接时磁盘I/O减少
2):连接查询时间减少
3):簇值相同的只存储一次


/************************************************************************************/
--一.存储问题

create cluster students_classes_cluster(class_id int);
--必须建立索引
create index students_classes_cluster_idx on cluster students_classes_cluster;

create table classes(class_id int,des varchar2(20))
cluster students_classes_cluster(class_id);

create table students(id int,name varchar2(20),class_id int)
cluster students_classes_cluster(class_id);

insert into classes values(1,'火箭班');
insert into classes values(2,'导弹班');
commit;

insert into students values(1,'小宝',1);
insert into students values(2,'至强',1);
insert into students values(3,'安卓',2);
insert into students values(4,'黑莓',2);
commit;

select distinct dbms_rowid.rowid_relative_fno(rowid) as fno,
dbms_rowid.rowid_block_number(rowid) as bno
from students;

select distinct dbms_rowid.rowid_relative_fno(rowid) as fno,
dbms_rowid.rowid_block_number(rowid) as bno
from classes;

alter system dump datafile 4 block 349;

select object_name
from dba_objects do
where do.object_id = to_number('d003', 'xxxxxxx');
--STUDENTS_CLASSES_CLUSTER

seg/obj: 0xd003 csc: 0x00.24e109 itc: 2 flg: E typ: 1 - DATA

data_block_dump,data header at 0x2b73e4df7064
===============
tsiz: 0x1f98
hsiz: 0x36
pbl: 0x2b73e4df7064
bdba: 0x0100015d
76543210
flag=--------
ntab=8 --8个表
nrow=4 --4行
frre=-1
fsbo=0x36
fseo=0x1f5f
avsp=0x1f29
tosp=0x1f29

0xe:pti[0] nrow=1 ffs=0
0x12:pti[1] nrow=0 ffs=1
0x16:pti[2] nrow=0 ffs=1
0x1a:pti[3] nrow=0 ffs=1
0x1e:pti[4] nrow=0 ffs=1
0x22:pti[5] nrow=0 ffs=1
0x26:pti[6] nrow=1 ffs=1
0x2a:pti[7] nrow=2 ffs=2

0x2e:pri[0] ffs=0x1f82
0x30:pri[1] ffs=0x1f77
0x32:pri[2] ffs=0x1f6b
0x34:pri[3] ffs=0x1f5f

block_row_dump:

tab0是簇本身,tab6是classes表,tab7是students表.

tab 0, row 0, @0x1f82
tl: 22 fb: K-H-FL-- lb: 0x0 cc: 1
curc: 3 comc: 3 pk: 0x0100015d.0 nk: 0x0100015d.0
col 0: [ 2] c1 02
select utl_raw.cast_to_number('c102') as class_id from dual;
--1 及簇中第一行

tab 6, row 0, @0x1f77
tl: 11 fb: -CH-FL-- lb: 0x0 cc: 1 cki: 0 --注意这里的cki,即与块中簇对应行,这里为第1行
col 0: [ 6] bb f0 bc fd b0 e0
select utl_raw.cast_to_varchar2(replace('bb f0 bc fd b0 e0', ' ')) des
from dual;
--火箭班

tab 7, row 0, @0x1f6b
tl: 12 fb: -CH-FL-- lb: 0x2 cc: 2 cki: 0
col 0: [ 2] c1 02
col 1: [ 4] d0 a1 b1 a6
select utl_raw.cast_to_number(replace('c1 02', ' ')) id,
utl_raw.cast_to_varchar2(replace('d0 a1 b1 a6',' ')) name
from dual;
--1,小宝

tab 7, row 1, @0x1f5f
tl: 12 fb: -CH-FL-- lb: 0x2 cc: 2 cki: 0
col 0: [ 2] c1 03
col 1: [ 4] d6 c1 c7 bf
select utl_raw.cast_to_number(replace('c1 03', ' ')) id,
utl_raw.cast_to_varchar2(replace('d6 c1 c7 bf',' ')) name
from dual;
--2,至强

综上:簇里面会将簇键汇总存储,即只存储一次,而簇表中的第行都会有个cki标识,来
标记这行对应簇中哪个键,只存标志位,而不重复存放。

/************************************************************************************/
--二.利用聚簇实现表的纵向分隔(分区是横向分隔)

考虑如下表:

create table users(user_id int primary key,total_score int,total_infull_num int);
insert into users values(1,1000000,20000);
commit;

--这是一张很普通游戏总表,其中user_id唯一标识一个玩家,而total_score代表玩家总的游戏
--净分,total_infull_num代表玩家总充值,设想下面一种情况:

1.玩家一直在使用客户端玩游戏,且total_score一直在变化
2.如果玩家在游戏过程中,点击web充值(此时total_score一直在变)

此时对应sql是这样的:

update users set total_score=total_score+10 where user_id=1;
update users set total_infull_num=total_infull_num+20 where user_id=1;

当然,如果这两条语句同时进行,那么必定会影响到玩家的游戏体验或者充值体验,因为
上面两条语句发生了锁急用。

下面利用簇来改善这种现象:

create cluster score_infull_cluster(user_id int);
create index score_infull_cluster_idx on cluster score_infull_cluster;

create table user_score(user_id int primary key,total_score int);
create table user_infull(user_id int primary key,total_infull_num int);

insert into user_score values(1,1000000);
insert into user_infull values(1,20000);
commit;

当我们在执行如下更新,则不会再有锁的问题:

update user_score set total_score=total_score+10 where user_id=1;
update user_infull set total_infull_num=total_infull_num+20 where user_id=1;

当然,像如上充值和游戏净分更新冲突的问题实属设计层面上的东西,也许聪明的你
在当初设计时就已经考虑到将这两个可能冲突的字段放到两张表里面,而oracle
cluster特性可以使这两张表更加紧密的联系在一起;当然簇的缺点很明显:即它将
表稀化,所以簇里面放多少张表还要依据实际情况来定。
请使用浏览器的分享功能分享到微信等