對於Oracle中的大表,我們可以采用分區表的方式進行優化,以提高訪問表的性能。
以下是對長慶物資系統的BILL表的優化過程:
分析:
BILL表有129個字段,24萬多條數據。
雖然數據量不是很大,但是字段過多,造成了讀取表的效率不高,經常出現資源競爭頻繁,I/O阻塞。
因此有必要對BILL表進行優化,提高效率。
對大表一般采用分區表的方式進行優化,由於Oracle沒有提供直接將普通表轉變為分區表的方式,必須通過重建表的方式進行優化,一般有三種方式實現,根據不同情況使用,
第一種:利用原表重建分區表,方法簡單易用,由於采用DDL語句,不會產生UNDO,且只產生少量REDO,效率相對較高,而且建表完成後數據已經在分布到各個分區中了;缺點是對於數據的一致性方面還需要額外的考慮。由於幾乎沒有辦法通過手工鎖定T表的方式保證一致性,在執行CREATE TABLE語句和RENAME T_NEW TO T語句直接的修改可能會丟失,如果要保證一致性,需要在執行完語句後對數據進行檢查,而這個代價是比較大的。另外在執行兩個RENAME語句之間執行的對T的訪問會失敗。適用於修改不頻繁的表,在閒時進行操作,表的數據量不宜太大。
第二種:使用交換分區的方法,只是對數據字典中分區和表的定義進行了修改,沒有數據的修改或復制,效率最高。如果對數據在分區中的分布沒有進一步要求的話,實現比較簡單。在執行完RENAME操作後,可以檢查T_OLD中是否存在數據,如果存在的話,直接將這些數據插入到T中,可以保證對T插入的操作不會丟失;缺點是仍然存在一致性問題,交換分區之後RENAME T_NEW TO T之前,查詢、更新和刪除會出現錯誤或訪問不到數據。如果要求數據分布到多個分區中,則需要進行分區的SPLIT操作,會增加操作的復雜度,效率也會降低;適用於包含大數據量的表轉到分區表中的一個分區的操作。應盡量在閒時進行操作。
第三種:使用在線重定義的方法,保證數據的一致性,在大部分時間內,表T都可以正常進行DML操作。只在切換的瞬間鎖表,具有很高的可用性。這種方法具有很強的靈活性,對各種不同的需要都能滿足。而且,可以在切換前進行相應的授權並建立各種約束,可以做到切換完成後不再需要任何額外的管理操作;缺點是實現上比上面兩種略顯復雜。
由於我們是在生產系統上進行優化,必須保證數據的完整性,所以選擇第三種方式進行優化,優化過程:
1、創建一個中間表,這個表要和BILL表的結構一致。
create table BILL_TEST
(
BILL_ID CHAR(8) not null,
PLAN_MAKE_TIME DATE,
UP_TIME DATE not null,
UP_NAME VARCHAR2(80),
SHENPI_PERSON VARCHAR2(20),
UP_MODE VARCHAR2(10) not null,
LOW_NAME VARCHAR2(80),
LOW_UP_TIME DATE,
UP_PERSON VARCHAR2(20) not null,
MAX_TYPE VARCHAR2(50) not null,
WARE_TYPE_SIZE VARCHAR2(1000) not null,
ERJI_WARE_TYPE VARCHAR2(8) not null,
ERJI_WARE_NUM NUMBER(15,4) not null,
ERJI_NEED_TIME DATE not null,
TUIJIAN_CORP VARCHAR2(20) default 1 not null,
SUPPLY_PINGKU CHAR(10) default 0,
JIHUA_ORDER_TIME VARCHAR2(20),
ORDER_TYPE VARCHAR2(50),
ORDER_MODE VARCHAR2(50),
ORDER_TIME DATE,
GET_WARE_TIME DATE,
SUPPLY_CORP VARCHAR2(500),
CAIGOU_WARE_NUM NUMBER(10,4),
CAIGOU_WARE_PRICE NUMBER(12,3),
CAIGOU_NEED_TIME DATE,
CAIGOU_NEED_ADDR VARCHAR2(200),
HETONG_ID VARCHAR2(100) default 0,
ZHILIANG_NOTE VARCHAR2(200),
ZHILIANG_MONEY NUMBER(12,2),
CONTENT VARCHAR2(200),
ERJI_WARE VARCHAR2(100),
WT_DATE DATE,
END_NUM VARCHAR2(20),
QICAI_WARE VARCHAR2(100),
SCCJ VARCHAR2(200),
JHDATE VARCHAR2(100),
JHNUM VARCHAR2(20),
SHOW NUMBER(1) default 0,
JH_ADDR VARCHAR2(200),
LAST_PRICE NUMBER(12,2),
PRE_PRICE NUMBER(12,2),
CLASS_ID VARCHAR2(20),
LD_MARK VARCHAR2(10) default 0,
ASK_PRICE NUMBER(12,2),
PLAN_CODE VARCHAR2(50),
ARRIVE_TIME DATE,
ARRIVE_WEIGHT VARCHAR2(50),
ARRIVE_QUALITY VARCHAR2(50),
BILL_STEP NUMBER(10,2) default 0,
XJD_CODE NUMBER(10),
XJD_DATE DATE,
XJD_SUPPLY VARCHAR2(1000),
OUT_FLAG VARCHAR2(2) default 0,
YY_PRICE NUMBER(12,2) default 0,
BASE_BILL VARCHAR2(8),
BASE_ID VARCHAR2(4),
TECK_ASK VARCHAR2(4000),
NEW_WARE_TYPE_SIZE VARCHAR2(1000),
NEW_ERJI_TYPE_SIZE VARCHAR2(100),
BIDE_YEAR VARCHAR2(4),
BIDE_ID VARCHAR2(5) default 0,
BIDE_FINISH NUMBER(1) default 0,
YSD_ID VARCHAR2(1000) default 0,
BG_TYPE NUMBER(1) default 0,
PLAN_CHECK VARCHAR2(20),
IF_ENERGY VARCHAR2(1) default 0,
LAST_SUPPLY VARCHAR2(200),
ASK_STEP NUMBER(4,1) default 0,
ASK_END NUMBER(1) default 1,
ASK_TIMES NUMBER(1) default 0,
CON_END_STEP NUMBER(1),
PZ_CODE VARCHAR2(50),
FP_CODE VARCHAR2(100),
QC_STEP NUMBER(2) default 0,
QC_PRICE NUMBER(12,2),
QC_SUPPLY VARCHAR2(200),
QC_SCCJ VARCHAR2(100),
QC_CON_ID VARCHAR2(20),
QC_JHDATE VARCHAR2(100),
QC_JHADDR VARCHAR2(100),
BJ_TYPE NUMBER(1),
BJ_INFO VARCHAR2(100),
FP_FILE VARCHAR2(20),
BJ_FILE VARCHAR2(100),
CC_STYLE NUMBER(1) default 0,
KROOM_ID VARCHAR2(40),
YSOVER VARCHAR2(10) default 0,
YSD_SJDHRQ VARCHAR2(11) default 0,
YSD_CPH VARCHAR2(10) default 0,
YSD_YDH VARCHAR2(10) default 0,
YSD_DUN NUMBER(10,2) default 0,
YSD_GEN NUMBER(10,2) default 0,
YSD_MI NUMBER(10,2) default 0,
YSD_SJBGH VARCHAR2(100) default 0,
YSD_KS VARCHAR2(1) default 0,
FLD_BH VARCHAR2(2000) default 0,
WZCD VARCHAR2(100),
QC_CODE NUMBER(10),
JH_STIME DATE,
CG_STIME DATE,
LD_STIME DATE,
CG_PTIME DATE,
JG_PTIME DATE,
IF_PRINT NUMBER(1) default 0,
KC_PRICE NUMBER(12,2),
KC_RATE NUMBER(8,3),
KC_ID NUMBER(8),
YSD1_FLAG NUMBER(1) default 0,
FLD_FLAG NUMBER(1) default 0,
YSD2_FLAG NUMBER(1) default 0,
OLD_PRICE NUMBER(12,2),
TECK_ASK_FILE VARCHAR2(40),
ZL_STIME DATE,
IF_JS NUMBER(1),
SITE_NAME VARCHAR2(200),
CLASS_ID_OLD VARCHAR2(20),
SD_FLAG NUMBER(1) default 0,
DJSD_FLAG NUMBER(1) default 0,
CON_JHDATE DATE,
CON_CONFIRM_DATE DATE,
RETURN_FLAG NUMBER(1),
PLAN_TYPE VARCHAR2(20),
WW_FLAG NUMBER(1) default 0,
YS_FLAG NUMBER(1) default 0,
RUN_TIME DATE,
OLD_WARE_NUM NUMBER(15,4),
JH_CTIME DATE default sysdate
)
tablespace DEMO_USER
partition by range(up_time)
(
partition p1 values less than (to_date('2002-1-1', 'yyyy-mm-dd')),
partition p2 values less than (to_date('2003-1-1', 'yyyy-mm-dd')),
partition p3 values less than (to_date('2004-1-1', 'yyyy-mm-dd')),
partition p4 values less than (to_date('2005-1-1', 'yyyy-mm-dd')),
partition p5 values less than (to_date('2006-1-1', 'yyyy-mm-dd')),
partition p6 values less than (to_date('2007-1-1', 'yyyy-mm-dd')),
partition p7 values less than (to_date('2008-1-1', 'yyyy-mm-dd')),
partition p8 values less than (maxvalue));
在新建的表中創建8個分區,將每一年的數據放在一個分區中,用up_time字段區分時間段。
2、開始重定向表
begin
dbms_redefinition.can_redef_table('demo_user','bill',dbms_redefinition.cons_use_pk);
dbms_redefinition.start_redef_table('demo_user','bill','bill_test',null,dbms_redefinition.cons_use_pk);
end;
3、創建與BILL_TEST相關聯的對象,保持和BILL表的一致
alter table BILL_TEST
add constraint TEST_BILL_UK21144125351128 unique (PLAN_CHECK)
using index
tablespace DEMO_USER; create index TEST_SY_BILL_BASE_ID on BILL_TEST (BASE_ID) tablespace DEMO_USER; create index TEST_SY_BILL_HETONG_ID on BILL_TEST (HETONG_ID) tablespace DEMO_USER; create index TEST_SY_BILL_MAX_TYPE on BILL_TEST (MAX_TYPE) tablespace DEMO_USER; create index TEST_SY_BILL_STEP on BILL_TEST (BILL_STEP) tablespace DEMO_USER; create index TEST_SY_BILL_UP_TIME on BILL_TEST (UP_TIME) tablespace DEMO_USER;
4、同步分區表
begin
dbms_redefinition.sync_interim_table('demo_user','bill','bill_test');
end;
5、完成重定向表
begin
dbms_redefinition.finish_redef_table('demo_user','bill','bill_test');
end;
6、刪除中間表
drop table bill_test;