(一)什么是間隔分區
間隔分區是Oracle 11.1引入的新功能,通過該功能,可以在輸入相應分區的數據時自動創建相應的分區。在沒有間隔分區技術之前,DBA通常會創建一個maxvalue分區以避免ORA-14400:插入的分區鍵值不能映射到任何分區("inserted partition key does not map to any partition") 錯誤。
作為范圍分區(range partition)的擴展,間隔分區命令數據庫在插入表中的數據超過所有現有范圍分區時自動創建指定間隔的分區。DBA必須至少指定一個范圍分區的較高值,稱為過渡點,數據庫會自動的為超出該過渡點的數據創建間隔分區,每個間隔分區的下邊界是先前范圍或間隔分區的上邊界。
(二)創建間隔分區
(2.1)間隔分區創建語法
CREATE TABLE table_name ( ... ) PARTITION BY RANGE(column1) INTERVAL expr [STORE IN (tablespace1,[tablespace2,...])] ( PARTITION partition_name1 VALUES LESS THAN(literal | MAXVALUE) [TABLESPACE tablespace1], PARTITION partition_name2 VALUES LESS THAN(literal | MAXVALUE) [TABLESPACE tablespace2] );
--PARTITION BY RANGE(column1):指定一個分區范圍列
--INTERVAL:指定分區間隔
--STORE IN:指定分區存儲的表空間
(2.2)間隔分區創建限制
間隔分區是范圍分區的擴展,其支持范圍有限,在Oracle 11g中,間隔分區只能指定一個分區鍵列,並且數據類型必須為NUMBER或者DATE類型。因為TIMESTAMP數據類型是DATE類型的擴展,可在分區鍵中使用。總結來說,間隔分區只支持NUMBER和TIME類型。
(2.3)INTERVAL關鍵字解讀
在創建自動間隔分區的時候,最為核心的就是”INTERVAL“關鍵字了。對於按照時間進行自動分區,INTERVAL后面可以跟隨NUMTOYMINTERVAL和NUMTODSINTERVAL。兩個關鍵字用法如下:
(2.3.1)NUMTOYMINTERVAL(x,c)
用法:x是一個數據,c是一個字符串,該函數是將x轉為interval year to month類型。常用單位有:”year“、”month“。
例子:當前時間加3年,當前時間加3個月
SELECT SYSDATE, SYSDATE + NUMTOYMINTERVAL(3,'year') AS "3年后" , SYSDATE + NUMTOYMINTERVAL(3,'month') AS "3個月后" FROM dual;
(2.3.2)NUMTODSINTERVAL(x,c)
用法:x是一個數據,c是一個字符串,該函數是將x轉為interval day to second類型。常用單位有:”day“、”hour“、”minute“、”second“。
例子:當前時間加1天、1小時、1分鍾、1秒鍾。
(三)按時間(年、月、日、周)創建間隔分區
(3.1)按”年“自動創建分區(關鍵字:NUMTOYMINTERVAL)
例子:創建按年自動分區表,按照員工生日(birthday字段),每年一個分區。
--創建按年分區表 CREATE TABLE interval_year_table01 ( employee_id NUMBER, employee_name VARCHAR2(20), birthday DATE ) PARTITION BY RANGE(birthday) INTERVAL (NUMTOYMINTERVAL(1,'year')) STORE IN (tbs01,tbs02,tbs03) ( PARTITION partition2014 VALUES LESS THAN(to_date('2015-01-01:00:00:00','yyyy-mm-dd hh24:mi:ss')), PARTITION partition2015 VALUES LESS THAN(to_date('2016-01-01:00:00:00','yyyy-mm-dd hh24:mi:ss')) );
(3.2)按”月“自動創建分區(關鍵字:NUMTOYMINTERVAL)
例子:創建按月自動分區表,按照員工生日(birthday字段),每月一個分區。
-- 創建按月分區表 CREATE TABLE interval_month_table01 ( employee_id NUMBER, employee_name VARCHAR2(20), birthday DATE ) PARTITION BY RANGE(birthday) INTERVAL (NUMTOYMINTERVAL(1,'month')) STORE IN (tbs01,tbs02,tbs03) ( PARTITION partition201401 VALUES LESS THAN(to_date('2014-02-01:00:00:00','yyyy-mm-dd hh24:mi:ss')) );
(3.3)按”天(日)“自動創建分區(關鍵字:NUMTODSINTERVAL)
例子:創建按天自動分區表,按照員工生日(birthday字段),每天一個分區。
-- 按天(日)創建分區 CREATE TABLE interval_day_table01 ( employee_id NUMBER, employee_name VARCHAR2(20), birthday DATE ) PARTITION BY RANGE(birthday) INTERVAL (NUMTODSINTERVAL(1,'day')) STORE IN (tbs01,tbs02,tbs03) ( PARTITION partition20140101 VALUES LESS THAN(to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')) );
(3.4)按”周“自動創建分區(關鍵字:NUMTODSINTERVAL)
例子:創建按周自動分區表,按照員工生日(birthday字段),每周一個分區。需要注意的是,這里使用的關鍵字與“天”分區一樣,都是“day”,只是改為了7天。
-- 按周創建分區 CREATE TABLE interval_week_table01 ( employee_id NUMBER, employee_name VARCHAR2(20), birthday DATE ) PARTITION BY RANGE(birthday) INTERVAL (NUMTODSINTERVAL(7,'day')) STORE IN (tbs01,tbs02,tbs03) ( PARTITION partition201401w VALUES LESS THAN(to_date('2014-01-07 00:00:00','yyyy-mm-dd hh24:mi:ss')) );
(3.4)按”小時“自動創建分區(關鍵字:NUMTODSINTERVAL)
-- 按”小時”進行分區
CREATE TABLE interval_hour_table01 ( employee_id NUMBER, employee_name VARCHAR2(20), birthday DATE ) PARTITION BY RANGE(birthday) INTERVAL (NUMTODSINTERVAL(1,'hour')) STORE IN (tbs01,tbs02,tbs03) ( PARTITION partition20140100 VALUES LESS THAN(to_date('2014-01-01 01:00:00','yyyy-mm-dd hh24:mi:ss')) );
除此之外,還可以按”分鍾“、”秒“進行自動分區。
(四)按數字(number)創建間隔分區
例子:按數字進行分區相對簡單,這里相近的10個數字進入同一個分區
CREATE TABLE interval_number_table01 ( employee_id NUMBER, employee_name VARCHAR2(20), birthday DATE ) PARTITION BY RANGE(employee_id) INTERVAL (10) STORE IN (tbs01,tbs02,tbs03) ( PARTITION partition10 VALUES LESS THAN(10) );
(五)關於間隔分區的常見問題
(5.1)如何將現有普通表轉換為間隔分區
可以使用如下命令將現有的范圍分區表轉換為間隔分區表,注意,僅僅支持范圍分區表:
ALTER TABLE <table_name> SET INTERVAL <number or interval expression>;
(5.2)如何為現有表設置新的間隔
可以使用如下命令修改間隔,該操作不會使index不可用:
ALTER TABLE <table_name> SET INTERVAL(interval express);
例子見MOS文檔(1479115.1)。
(5.3)如何為間隔分區指定/更改表空間
INTERVAL子句的STORE IN用於指定創建間隔分區的表空間。如果指定了表空間列表,將以循環方式在這些表空間上創建間隔分區。
INTERVAL expr [STORE IN (tablespace1,[tablespace2,...])]
需要注意的是,在INTERVAL子句中使用”PARTITION“創建的范圍分區需要指出表空間,否則會將范圍分區創建到用戶默認的表空間中,而不是[STORE IN]的表空間中。
對於已經創建的分區,可以使用以下命令將其移動到特定的表空間:
--移動分區到特定表空間 ALTER TABLE <table_name> MOVE PARTITION <partition_name> TABLESPACE <tablespace_name>; --注:移動分區會導致全局索引失效,需謹慎
(5.4)自動創建的間隔分區的名稱是什么
數據庫創建的間隔分區的名稱是系統自動生成的,可以通過dba_tab_partition視圖查看。目前無法為分區指定創建模板,但是可以重命名分區。
例子:自動創建的表空間的名稱
insert into INTERVAL_NUMBER_TABLE01 values (201209, 'name09'); insert into INTERVAL_NUMBER_TABLE01 values (201210, 'name10'); insert into INTERVAL_NUMBER_TABLE01 values (201211, 'name11'); insert into INTERVAL_NUMBER_TABLE01 values (201212, 'name12'); insert into INTERVAL_NUMBER_TABLE01 values (201301, 'name01'); insert into INTERVAL_NUMBER_TABLE01 values (201402, 'name02'); insert into INTERVAL_NUMBER_TABLE01 values (201503, 'name03'); SQL> select table_owner,table_name,partition_name,high_value,tablespace_name,interval 2 from dba_tab_partitions 3 where table_name = 'INTERVAL_NUMBER_TABLE01'; TABLE_OWNER TABLE_NAME PARTITION_NAME HIGH_VALUE TABLESPACE_NAME INTERVAL -------------- ------------------------------ ----------------- ------------ ----------------- -------- LIJIAMAN INTERVAL_NUMBER_TABLE01 PARTITION10 10 USERS NO LIJIAMAN INTERVAL_NUMBER_TABLE01 SYS_P54 20 TBS02 YES LIJIAMAN INTERVAL_NUMBER_TABLE01 SYS_P55 110 TBS02 YES LIJIAMAN INTERVAL_NUMBER_TABLE01 SYS_P56 120 TBS03 YES LIJIAMAN INTERVAL_NUMBER_TABLE01 SYS_P57 130 TBS01 YES --備注:INTERVAL = 'YES'代表自動創建的分區
(5.5)使用DBMS_METADATA.GET_DDL檢索表時,為什么缺少系統生成的間隔分區?
"DBMS_METADATA.GET_DDL"只提供用戶手段創建的分區,而不提供系統自動生成的分區。以下為測試例子:
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','INTERVAL_NUMBER_TABLE01','LIJIAMAN') FROM DUAL;
DBMS_METADATA.GET_DDL('TABLE', -------------------------------------------------------------------------------- CREATE TABLE "LIJIAMAN"."INTERVAL_NUMBER_TABLE01" ( "EMPLOYEE_ID" NUMBER, "EMPLOYEE_NAME" VARCHAR2(20), "BIRTHDAY" DATE ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE( BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" PARTITION BY RANGE ("EMPLOYEE_ID") INTERVAL (10) STORE IN ("TBS01", "TBS02", "TBS03") (PARTITION "PARTITION10" VALUES LESS THAN (10) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 8388608 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" )
如果要輸出系統自動創建的分區的腳本,需將DBMS_METDATA的EXPORT參數設置為true
exec dbms_metadata.set_transform_param(dbms_metadata.SESSION_TRANSFORM,'EXPORT',true);
(六)關於間隔分區的bug
以前在使用分區表時,遇到過由延遲段創建(deferred_segment_creation)引起的段分配異常問題。間隔分區也有類似的bug,使用需要謹慎。
Bug 16042673 - Database hang when system trying to add interval partition to the table (Doc ID 16042673.8)
Symptoms:
Related To:
- Hang (Process Hang)
- Waits for "library cache lock"
- Waits for "library cache load lock"
Description
This bug is only relevant when using Partitioned Tables
Concurrent insert statements issued against an interval
partitioned table resulting in the creation of a new partition
blocks remaining inserts into the same table.
Rediscovery Notes
If concurrent insert statements are issued against an interval
partitioned table and the insert statement which results in the
creation of a new partition blocks all the other inserts into the
table, then we might be encountering this bug.
(七)間隔分區的利弊思考
好處:間隔分區通過系統自動創建分區,減少了DBA的日常運維工作,避免了ORA-14400這類錯誤,每年年終不需要為下一年手動創建分區,想想還是挺開心的;
壞處:因為系統自動創建分區名稱,我們無法通過分區名稱來判斷數據的存放位置,增加了后期的維護難度。舉個例子,如果是DBA手動維護,假設表的分區”part_201901“存儲的就是2019年1月的數據,假如我們想要刪除1月份的數據,直接刪除該分區即可,如果數據庫里面有500個類似的表,直接寫批量腳本”ALTER TABLE <table_name> DROP PARTITION part_201901“就將全部表的1月份的數據刪除了,但是對於系統自動創建的分區,在不同的表里面,2019年1月的數據對應的分區名不同,自然無法使用腳本批量刪除,即使有腳本,也非常麻煩。
-------------------------------------------------------------------------------------------------------
個人分區(partition)技術相關文檔:
1. [oracle]分區表學習
2. [Oracle]分區索引
3. Oracle分區表刪除分區引發錯誤ORA-01502: 索引或這類索引的分區處於不可用狀態
4. Oracle split分區表引起ORA-01502錯誤
5. Oracle在線重定義(online redefinition)--將普通表改為分區表
參考文檔:
1. Interval Partitioning Essentials - Common Questions - Top Issues (Doc ID 1479115.1)
2. How to Build an INTERVAL PARTIONED Table using a NUMBER datatype for the INTERVAL Partition. (Doc ID 1514047.1)
3. Bug 16042673 - Database hang when system trying to add interval partition to the table (Doc ID 16042673.8)
-------------------------------------------------------------------------------------------------------