变态方式实现大数据量转换的小表热点盘问题

遇到一个认为有点奇怪的问题。

有两个表,大概都是3亿左右的数据,A表有A1字段 B表有B1字段,都是通过其他表来更新的。分别为A1使用C表,B1使用D表,不同的是C表很小只有近1万行,D表很大,也有3亿。(C表后面成为小表,D表成为大表)

因为B表有3亿数据,需要从D表这个3亿数据来获取更新,开始的时候我很为这个担心,打算给D表分表来做,但是实际测试了一下,发现居然B更新的比A表快。百思不得其解。去请教DBA,分析后发现存在热点盘问题。

因为我更新的时候,都是根据索引字段分模来更新的,每个表都分了50个左右的模,由于更新的时候读小表的时候,每次基本都会读到相同的磁盘,所以就存在热点,而读大表的时候,读到相同磁盘的概率就很低,这样,B表的更新就会比A表快了。

虽然有点变扭,但是原因确实应该就是这样。但是如何解决呢?

我想到的第一种方式,就是把小表的数据keep进缓存中,也就是说,访问小表的时候,尽快使用数据库的缓存(可以参见https://www.cnblogs.com/Richardzhu/p/3437925.html)

按照这篇文章的指引我将小表搞进了内存中,效率虽然有一点提升,但是效果并不明显。这个原因我还是没想清楚到底为什么。

第二种方式,按照DBA的指点,我把小表的pctfree(可以参见https://www.cnblogs.com/linjiqin/archive/2012/01/16/2323320.html)改大,改为了70,这样能够使表存储的更加分散,可能因为我这个表实在太小,这个基本没起啥作用。

最后实在是没辙,就想到,既然是分模导致的问题,为啥不直接把这个表按照分模逻辑再拆分?这样,访问的时候就会更加分散,我将小表增加了分模的字段,直接复制了50份,原来索引,增加取模ID建为复合索引。同样再做拆分,将表keep进缓存中。

--表

create table prod_attr_spec_on_mod pctfree 70 as select * from prod_attr_spec where 1=2 ;

alter table prod_attr_spec_on_mod add TABLE_NAME VARCHAR2(50);

alter table prod_attr_spec_on_mod add FUN_NAME VARCHAR2(100);

alter table prod_attr_spec_on_mod add PROCESS_MOD_NUM number;

declare

i number ;

begin

for i in 0..50 loop

insert into prod_attr_spec_on_mod

select t.* ,

'SERV_ATTR','GET_PRODUCT_ATTR_ID_BY_OLD_ONMOD',i

from prod_attr_spec t ;

commit ;

end loop;

end ;

--索引

create index IDX_PRIDATTRIDPRODATTRonmod on prod_attr_spec_on_mod (attr_id ,PROCESS_MOD_NUM) ;

--keep 进内存

alter table prod_attr_spec_on_mod storage(buffer_pool keep);

alter INDEX IDX_PRIDATTRIDPRODATTRonmod STORAGE (BUFFER_POOL KEEP);

Alter table prod_attr_spec_on_mod cache;

--表分析

begin

dbms_stats.gather_table_stats

(ownname => 'GJ_USER',

tabname => 'prod_attr_spec_on_mod',

estimate_percent=> 100,

method_opt => 'for all columns',

cascade => true,

degree =>16

);

end ;

这样做了以后,效率提升了一倍还多,方法确实是比较变态,但是还是挺实用的。

相关推荐