1. 程式人生 > >資料庫優化之高效率調優oracle億級別表

資料庫優化之高效率調優oracle億級別表

2017年在省公司做一個專案,涉及到一個億級別的大表操作,過程中遇到了很多坑,走過後記錄如下,方便今後回憶。

Oracle資料庫是一種事務性資料庫,對刪除、修改、新增操作會產生undo和redo兩種日誌,當一次提交的資料量過大時,資料庫會產生大量的日誌寫檔案IO操作,導致資料庫操作效能下降,尤其是對一張記錄過億的表格進行操作時需要注意以下事項:

1、操作大表必須知道表有多大

select sum(bytes)/(1024*1024) as "size(M)" from user_segments where segment_name=upper('ipdetail');

通過這條命令可以在大表匯入及使用時實時查詢進度和該表所佔的實際儲存空間。

知道一個使用者下的所有表各佔多大儲存空間

select 'select sum(bytes)/(1024*1024) as "size(M)" from user_segments where segment_name=upper('''||tname||''')' from tab;

2、大於1000w記錄的表格最好分割槽或分表處理,如果分表涉及的業務調整量太大,可以先考慮分割槽儲存

比如可以按照IP數字的範圍大概將每2000萬條記錄放入一個分割槽表空間中進行儲存。

create table testipdetail (ipadd varchar2(20),numip number,isp varchar2(255),country varchar2(255),province varchar2(255),city varchar2(255),used varchar2(255),create_date date default sysdate,creater_id number,sts number)

partition by range (numip)

(partition ip1 values less than (1000000000),

partition ip2 values less than (1930000000),

partition ip3 values less than (2285000000),

partition ip4 values less than (3080000000),

partition ipmax values less than (3774873599)

 )

通過分割槽處理後,9G的表資料基本均勻的儲存在5個表空間中,經過測試大表分割槽後比表儲存在單一分割槽上的insert效率高40%,但是update效率沒有顯著提升。

3、儘量不要使用全表update操作

如果有對一個欄位進行整體修改的計劃,建議使用新建表格的方式。

--新建一張和待修改表格一樣表結構的新表

create table t2 as select * from ipdetail where 1=2

--修改表格的屬性為不歸檔模式,實際效果不大

alter table t2 nologging;

--已不記錄日誌的形式進行批量插入/*+ APPEND */

insert /*+ APPEND */ into T2 select ipadd,numip,isp,country,province,city,used,create_date,1,0 from ipdetail

--插入結束後一定要記得提交,否則查詢會報錯

Commit

4、大表update資料前先建索引

比如下面一條語句通過先建好t2表格的numip欄位索引以及hbipdetail表格的numip欄位索引,通過引入並行操作機制,這條涉及530多萬行的更新語句只需要195秒執行完畢。

update /*+parallel(t2,4)*/  t2 i set city=(select /*+parallel(hbipdetail,4)*/  city from hbipdetail h where i.numip=h.numip and rownum=1),sts=1  where i.province='湖北'

--執行完後必須先提交,否則報錯。

Commit

5、更新語句加入rownum數量限制,切分一次更新的數量集

這種方法首先需要程式設計實現,將更新總量除以每次更新的資料量集,做迴圈列印日誌,這種處理方案的好處是可以知道更新的具體進度,但是對於提高處理效率沒有幫助。

更新500000條,共更新500000條記錄!2017-10-14 13:05:28

更新500000條,共更新1000000條記錄!2017-10-14 13:05:44

更新500000條,共更新1500000條記錄!2017-10-14 13:06:00

更新500000條,共更新2000000條記錄!2017-10-14 13:06:15

更新500000條,共更新2500000條記錄!2017-10-14 13:06:29

更新500000條,共更新3000000條記錄!2017-10-14 13:06:43

更新500000條,共更新3500000條記錄!2017-10-14 13:06:58

無論如何調整每次更新的資料量,時間的變化總是線性關係

6、大表操作表鎖死後如何處理

首先查出鎖死的具體程序,主要關注刪除號

SELECT dob.OBJECT_NAME Table_Name,lo.SESSION_ID||', '||vss.SERIAL# 刪除號,

lo.locked_mode,lo.SESSION_ID, vss.SERIAL#,vss.action Action,vss.osuser OSUSER, vss.LOGON_TIME,

vss.process AP_PID, VPS.SPID DB_PID ,vss.*

From v$locked_object lo, dba_objects dob, v$session vss, V$PROCESS VPS

Where lo.OBJECT_ID = dob.OBJECT_ID

and lo.SESSION_ID = vss.SID

AND VSS.paddr = VPS.addr

order by 2,3,DOB.object_name

刪除鎖死程序

ALTER system kill session ‘sessionid,serialid'

總結:

對大表操作的原則是:

1、索引和表不建議建在同一個表空間;

2、表本身最好通過業務規則分佈儲存在多個不同的表空間中,提高併發訪問效率;

3、insert操作前先將表設定為nologging狀態,語句中注意新增/*+ APPEND */識別符號;

4、update操作儘量不要做全表,如果非要做全表不如轉為insert操作,效率提高十幾倍;

5、加入並行操作符可以小量提升update效能,/*+parallel(4)*/,操作符中的數值代表使用cpu執行緒數;