遇到一個認為有點奇怪的問題。 有兩個表,大概都是3億左右的數據,A表有A1欄位 B表有B1欄位,都是通過其他表來更新的。分別為A1使用C表,B1使用D表,不同的是C表很小隻有近1萬行,D表很大,也有3億。(C表後面成為小表,D表成為大表) 因為B表有3億數據,需要從D表這個3億數據來獲取更新,開始的 ...
遇到一個認為有點奇怪的問題。
有兩個表,大概都是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 ;
這樣做了以後,效率提升了一倍還多,方法確實是比較變態,但是還是挺實用的。