業務場景:
表xngul 大小大于 100G。
上面有(id)是number型自增字段,且是pk。
現在有需求要對這個表進行全表掃描,如果直接 select * from xngul, 則至少要半個小時,
而且一次性返回數據過多,應用程序無法處理。
所以想了辦法化整為零,將這個表分段,分段讀取。
有以下三種方式。
*******I.兩個步驟,一個取分段的頭尾,一個按頭尾取分段內數據。*********
-取分段的頭尾
select min(id) as min_id,
max(id) as max_id
from
(select /*+index (xngul xngul_pk)*/id
from xngul
where id > :last_max_id
order by id)
where rownum <= :page_size;
-按頭尾取中間的數據
select *
from xngul
where id between :min_id and :max_id;
**********************************************************************
――――――――――――――――――――――――――――-
**************II.一個步驟,完成分段和取數據。*************************
-在一個sql中完成分段和取數據
select /*+ordered use_nl(b)*/
b.*
from
(select id
from
(select /*+index (xngul xngul_pk)*/id
from xngul
where id > :last_max_id
order by id) a
where rownum <= :page_size) a, xngul b
where a.id=b.id;
**********************************************************************
――――――――――――――――――――――――――――-
********III.借助一個表,實現多個進程并發處理。************************
-將分段數據記錄到表中,并給每個段賦予一個 batch_id 和 batch_status
insert into batch
(batch_id, batch_status, ceiling_id, floor_id)
select
seq_batch.nextval as batch_id,
’not dealed’ as batch_status,
max(id) as ceiling_id,
min(id) as floor_id
from
(select /*+index (xngul xngul_pk)*/id
from xngul
where id > :last_max_id
order by id)
where rownum <= :page_size;
-多進程并發取未處理的batch_id
select batch_id, ceiling_id, floor_id
from batch for update nowait
where batch_status=’not dealed’
and rownum<=1;
-取該batch_id的明細數據
select *
from xngul
where id between :min_id and :max_id;
-處理完畢后,更新該batch_status
update batch
set batch_status=’has dealed’
where batch_id=:batch_id;
**********************************************************************
該方式還可以再擴展:
1,如果對數據實時性要求不高,可以在standby上按rowid來分段讀取,效率會更高。
2,如果要做表連接,則可以對其中的大表做這個分段,分段的結果再來跟其他小表做連接,同樣可以達到化整為零的目的。
原文轉自:http://blogread.cn/it/article/972