過久沒有更新技術博客,後續仍是保持之前的更新速度,走向2020的學習之路,也歡迎你們一塊兒來學習學習。最後撈一下之前發的面試文章總結,後續將繼續更新:java
分區表是將大表的數據分紅稱爲分區的許多小的子集,分區表的種類劃分主要有:range(範圍)、list(列表)和hash(散列)分區。劃分依據主要是根據其表內部屬性。程序員
分區表能夠建立其獨特的分區索引,分區表能夠從物理上將一個大表分紅幾個小表,可是從邏輯上來看,仍是一個大表。
表內的數據量很大的時候,影響到業務/技術方容忍的最大查詢時間。但數據量並非判斷是否須要建立分區表的唯一條件,若是表內的數據都是基礎數據、其數據查詢都頻率高,這樣不建議使用分區表。一般狀況下,能夠將數據進行分段處理。面試
表的大小超過2GB可進去分區表改造
範圍分區(range):基於一個範圍將表的數據分配到其所屬的分區內。算法
若是須要將行映射到基於列值範圍的分區時,就使用範圍分區方法--條件是數據能夠被劃分紅邏輯範圍;當數據在整個範圍內能被均等地劃分時性能最好,明顯不能均分時須使用其餘分區方式「範圍」是在建立分區表時指定的分區鍵決定的,分區方式是最爲經常使用的,而且分區鍵常常採用日期sql
列表分區(list):基於列某個特性分配其所屬的分區數據庫
該分區的特色是某列的值只有幾個,基於這樣的特色咱們能夠採用列表分區
散列分區(hash):在列值上使用散列算法來分配其所屬分區segmentfault
當列的值沒有合適的條件時,建議使用散列分區,經過在I/O設備上進行散列分區,使得這些分區大小一致。
此次主要討論的是以範圍分區(range),而且以日期做爲分區鍵。數組
在作表分區前,須要表統計分析,各個表、索引空間存儲大小,每一年或者每月表的增加率等(能夠找DBA)。這邊提供DBA經常使用系統表,視圖——https://docs.oracle.com/cd/B1...性能優化
select t.owner,t.segment_name,t.tablespace_name,sum(bytes/1024/1024/1024) gb from dba_segments t where t.segment_name in (select t2.OBJECT_NAME from dba_objects t2 where t2.OBJECT_TYPE = 'TABLE' AND t2.owner=upper('tabel_owner') ) group by t.owner,t.segment_name,t.tablespace_name order by 4 desc;
select round(sum(bytes) / 1024 / 1024 / 1024, 4) IDX_GB --表上索引對象佔用空間 from dba_segments where owner || segment_name in(select owner || index_name from dba_indexes where table_owner = upper('table_name') and table_name = upper('table_owner'));
前面表的各項指標都分析統計出來,那就開始實際操做起來,首先進行的小於100G的改造方案:多線程
Note:在進行接下來的腳本的時候記得定義好所需的變量declare
v_table_name varchar2(100) := upper('表名');
----建表變量
v_sql_temp1 varchar2(1000);
v_sql_temp2 varchar2(1000);
v_sql_temp3 varchar2(1000);
----屬主變量
v_owner varchar2(100) := upper('表屬主');
-----輸出變量
type remark_list is varray(60) of varchar2(3000);
v_output_list remark_list;
-----受權變量
v_grantee varchar2(100);
v_grant_sql varchar2(1000);
type type_array is table of varchar(20) index by binary_integer;
grantee_list type_array;
步驟以下:
建立分區表--腳本生成模板1:
羅列全部字段模板,涉及到dba_tab_columns(表的列信息)
-----------1.新建分區臨時表 v_sql_temp1 := 'CREATE TABLE ' || v_owner || '.' || v_table_name || '_P( '; select COLUMN_NAME ||' '|| decode( DATA_TYPE,'DATE',DATA_TYPE, DATA_TYPE||'('|| DATA_LENGTH || ')') || decode(NULLABLE,'N',' not null','') || ',' bulk collect into v_output_list from dba_tab_columns t where table_name =v_table_name order by t.COLUMN_ID ; dbms_output.put_line(v_sql_temp1); for i in 1 ..v_output_list.count loop --去掉數組中的最後一個字段字符中的逗號"," if i = v_output_list.count then select REPLACE(v_output_list(i),',',' ') into v_sql_temp2 from dual; dbms_output.put_line(v_sql_temp2); else dbms_output.put_line(v_output_list(i)); end if; end loop; --輸出分區信息 v_sql_temp3 := ')PARTITION BY RANGE (ARCHIVE_DATE) INTERVAL (NUMTOYMINTERVAL(1, ''YEAR'')) (PARTITION ' || v_table_name || '_2019' || ' VALUES LESS THAN (TO_DATE(''2020-01-01'', ''YYYY-MM-DD'')))ENABLE ROW MOVEMENT MONITORING INITRANS 6;'; dbms_output.put_line(v_sql_temp3);
生成的模板:
CREATE TABLE PASDATA.CLM_PERSON_HOSPITAL_P( CREATED_BY VARCHAR2(100) not null, CREATED_DATE DATE not null, UPDATED_BY VARCHAR2(100) not null, UPDATED_DATE DATE not null, ID_CLM_PERSON_HOSPITAL VARCHAR2(32) not null, REPORT_NO VARCHAR2(30) not null, ID_CLM_CHANNEL_PROCESS VARCHAR2(32) not null, CASE_TIMES NUMBER(22) not null, HOSPITAL_CODE VARCHAR2(22), HOSPITAL_NAME VARCHAR2(100), SUBJECT_CODE VARCHAR2(20), BED_CODE VARCHAR2(100), START_DATE DATE, END_DATE DATE, MIGRATE_FROM VARCHAR2(1), AFFIRM_SIGN VARCHAR2(1) not null, DOCUMENT_GROUP_ID VARCHAR2(30), HOSPITALIZATION_NUMBER VARCHAR2(30), HOSPITALIZE_DAYS NUMBER(22), ARCHIVE_DATE DATE )PARTITION BY RANGE (ARCHIVE_DATE) INTERVAL (NUMTOYMINTERVAL(1, 'YEAR')) ( PARTITION CLM_PERSON_HOSPITAL_2018 VALUES LESS THAN (TO_DATE('2019-01-01', 'YYYY-MM-DD')) )ENABLE ROW MOVEMENT MONITORING INITRANS 6;
建立分區表--腳本生成模板2:
declare v_table_name varchar2(100) := upper('表名'); -------建表變量 v_sql_temp1 varchar2(1000); v_sql_temp2 varchar2(1000); v_sql_partion varchar2(1000); ----屬主變量 v_owner varchar2(100) := upper('表屬主'); -----輸出變量 若是字段數量超過60個,修改數組大小便可 type remark_list is varray(60) of varchar2(3000); v_remark_list remark_list; begin ----在begin後面加上DBMS_OUTPUT.ENABLE(buffer_size => null) ,表示輸出buffer不受限制。 DBMS_OUTPUT.ENABLE(buffer_size => null); ----------------------------------------1.新建分區臨時表---------------------------------- v_sql_temp1 := 'CREATE TABLE ' || v_owner || '.' || v_table_name || '_P PARTITION BY RANGE (ARCHIVE_DATE) INTERVAL (NUMTOYMINTERVAL(1, ''YEAR'')) ('; v_sql_temp2 := 'PARTITION ' || v_table_name || '_2019' || ' VALUES LESS THAN (TO_DATE(''2020-01-01'', ''YYYY-MM-DD''))'; v_sql_temp3 := ')ENABLE ROW MOVEMENT MONITORING INITRANS 6 AS SELECT * FROM ' || v_owner || '.' || v_table_name || ' WHERE 1=0;'; dbms_output.put_line(v_sql_temp1 || v_sql_temp2 || v_sql_temp3);
生成的模板:
CREATE TABLE PASDATA.EDR_APPLY_PLAN_INFO_P PARTITION BY RANGE (ARCHIVE_DATE) INTERVAL (NUMTOYMINTERVAL(1, 'YEAR')) ( PARTITION PART_BEFORE_2018 VALUES LESS THAN (TO_DATE('2018-01-01', 'YYYY-MM-DD')) )ENABLE ROW MOVEMENT MONITORING INITRANS 6 AS SELECT * FROM PASDATA.EDR_APPLY_PLAN_INFO WHERE 1=0;
------- 2.對分區新表字段增長默認值 select 'alter table ' || t.owner || '.' || t.table_name || '_NEW modify ' || t.column_name || ' default 記得填默認值;' bulk collect into v_output_list from DBA_TAB_COLS t where t.TABLE_NAME = v_table_name and t.owner = v_owner and t.data_default is not null; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
添加表以及字段的註釋涉及到表 dba_tab_comments(表註釋信息)、dba_col_comments(列註釋信息)
------------- 3.對分區新表的表名,字段增長註釋 select 'comment on table ' || a.owner || '.' || a.table_name || '_P is ''' || a.comments || ''';' bulk collect into v_output_list from dba_tab_comments a where a.table_name = upper(v_table_name) and a.owner = upper(v_owner); for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop; select 'comment on column ' || owner || '.' || table_name || '_P.' || column_name || ' is ' || '''' || comments || ''';' bulk collect into v_output_list from dba_col_comments where table_name = v_table_name; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
dbms_output.put_line('insert /*+ append parallel(A, 4) */ into ' || v_owner || '.' || v_table_name || '_P A select /*+ parallel(T, 4) */ * from ' || v_owner || '.' || v_table_name || ' T;'); dbms_output.put_line('commit;');
建立分區表索引涉及到dba_indexes (用戶模式的索引信息)、dba_ind_columns( 索引與表字段的相關信息)
select 'create ' || decode(a.uniqueness, 'UNIQUE', 'UNIQUE', '') || ' index ' || a.owner || '.' || a.index_name || '_N on ' || a.table_owner || '.' || a.table_name || '_P (' || (select wm_concat(b.column_name) from dba_ind_columns b where b.index_name = a.index_name and b.table_owner = v_owner) || ') initrans 16 PARALLEL 8 online;' bulk collect into v_output_list from dba_indexes a where a.table_name = v_table_name and a.index_type != 'LOB'; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
建立分區表索約束涉及到dba_cons_columns(數據庫全部列的約束信息)、dba_constraints( 數據庫中全部表的全部約束定義),當dba_constraints中的constraint_type值爲爲p時爲表主鍵,值爲R時爲外鍵。
建立主鍵約束
----建立主鍵約束 select 'ALTER TABLE ' || a.owner || '.' || a.table_name || '_P ADD CONSTRAINT ' || a.constraint_name || '_N PRIMARY KEY (' || a.column_name || ');' bulk collect into v_output_list from dba_cons_columns a where a.constraint_name = (select constraint_name from dba_constraints b where b.table_name = v_table_name and b.owner = a.owner and constraint_type = 'P') and a.owner = v_owner; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
建立外鍵約束
-----(若是有外鍵的話,建立外鍵約束) select 'alter table ' || a.owner || '.' || a.table_name || '_P add constraint ' || a.constraint_name || '_N foreign key(' || b.column_name || ') references ' || (select c.owner || '.' || c.table_name || '(' || c.column_name || ')' from dba_cons_columns c, dba_constraints d where c.constraint_name = d.constraint_name and d.constraint_type = 'P' and c.constraint_name = a.r_constraint_name and c.owner = v_owner and d.owner = v_owner) || ';' bulk collect into v_output_list from dba_constraints a, dba_cons_columns b where a.constraint_name = b.constraint_name and a.table_name = v_table_name and a.constraint_type = 'R'; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
select 'alter index ' || a.owner || '.' || a.index_name || ' rename to ' || a.index_name || '_T;' bulk collect into v_output_list from dba_indexes a where a.table_name = v_table_name and a.index_type != 'LOB'; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop; select 'alter table ' || a.owner || '.' || a.table_name || ' rename constraint ' || a.constraint_name || ' to ' || a.constraint_name || '_T;' bulk collect into v_output_list from dba_constraints a where a.table_name = v_table_name and a.constraint_type in ('P', 'R'); for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
select 'alter index ' || a.owner || '.' || a.index_name || '_N rename to ' || a.index_name || ';' bulk collect into v_output_list from dba_indexes a where a.table_name = v_table_name and a.index_type != 'LOB'; for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop; select 'alter table ' || a.owner || '.' || a.table_name || '_P rename constraint ' || a.constraint_name || '_N to ' || a.constraint_name || ';' bulk collect into v_output_list from dba_constraints a where a.table_name = v_table_name and a.constraint_type in ('P', 'R'); for i in 1 .. v_output_list.count loop dbms_output.put_line(v_output_list(i)); end loop;
給rename後的分區新表受權涉及到dba_tab_privs(數據庫全部列的受權信息),查詢全部的受權列表進行輸出,定義好grantee_list、v_grant_sql等變量
select distinct (t.grantee) bulk collect into grantee_list from dba_tab_privs t where (t.owner = upper(v_owner)) and t.table_name = v_table_name; for i in 1 .. grantee_list.count loop v_grantee := grantee_list(i); select 'grant ' || (select wm_concat(t.privilege) from dba_tab_privs t where t.table_name = v_table_name and t.grantee = v_grantee) || ' on ' || t.owner || '.' || t.table_name || ' to ' || t.grantee || ';' into v_grant_sql from dba_tab_privs t where t.table_name = v_table_name and t.grantee = v_grantee and rownum = 1; dbms_output.put_line(v_grant_sql); end loop;
當分區表的改造完成後保險地進行驗證一下,數據量,索引,受權列表
對比索引
select * from dba_indexes a where a.table_name = 'CLM_HIS_RECIPE_DETAIL_NEW' and a.index_type != 'LOB';
對比受權用戶列表
select * from dba_tab_privs t where t.table_name in ('CLM_PERSON_HOSPITAL_NEW') and t.owner = 'CLAIMDATA';
各位看官還能夠嗎?喜歡的話,動動手指點個💗,點個關注唄!!謝謝支持!歡迎關注公衆號【Ccww技術博客】,原創技術文章第一時間推出