• 间隔分区 Interval Partition partition_name, interva


      分区(Partition)一直是Oracle数据库引以为傲的一项技术,正是分区的存在让Oracle高效的处理海量数据成为可能,在Oracle 11g中,分区技术在易用性和可扩展性上再次得到了增强。在10g的Oracle版本中,要对分区表做调整,尤其是对RANGE分区添加新的分区都需要DBA手动定期添加,或都使用存储过程进行管理。在11G的版本中的Interval Partition不再需要DBA去干预新分区的添加,Oracle会自动去执行这样的操作,减少了DBA的工作量。Interval Partition是Range分区的一个扩展。

    使用Interval Partition也有一些限制:

    You can only specify one partitioning key column, and it must be of NUMBER or DATE type.

    Interval partitioning is not supported for index-organized tables.

    You cannot create a domain index on an interval-partitioned table.

    Interval partitioning is not supported at the subpartition level. ...
     Interval Partition也可以创建复合分区:

    Interval-range

    Interval-hash

    Interval-list

     创建Interval分区表:

    CREATE TABLE t
    (
      id number,
      create_date  date
    )
    partition by range(create_date) interval(numtoyminterval(1,'MONTH'))
    (
      partition p201303 values less than (date '2013-03-01'),
      partition p201304 values less than (date '2013-04-01'),
      partition p201305 values less than (date '2013-05-01')
    ); 
    这里就创建了一个每个月会自动生成一个分区的表。

    interval函数以及numtoninterval函数的说明

    SQL> SQL>  select partition_name, interval, high_value from dba_tab_partitions where table_owner=user and table_nam                 e = 'T' order by partition_position;
     
    PARTITION_NAME                 INT HIGH_VALUE
    ------------------------------ --- --------------------------------------------------------------------------------                 -----
    P201303                        NO  TO_DATE(' 2013-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    P201304                        NO  TO_DATE(' 2013-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    P201305                        NO  TO_DATE(' 2013-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    --可以发现interval=NO,目前是指定的3个分区。

    接着插入一笔非这个指定分区的数据:

    SQL> insert into t values(1 ,date'2013-05-11');
     
    1 row created.
     
    SQL> commit;
     
    Commit complete.
     
     
    SQL> select partition_name, interval, high_value from dba_tab_partitions where table_owner=user and table_name = 'T' order by partition_position;
     
    PARTITION_NAME                 INT HIGH_VALUE
    ------------------------------ --- -------------------------------------------------------------------------------------
    P201303                        NO  TO_DATE(' 2013-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    P201304                        NO  TO_DATE(' 2013-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    P201305                        NO  TO_DATE(' 2013-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    SYS_P41                        YES TO_DATE(' 2013-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    发现自动建立了一个新分区sys_p41,interval值为YES,说明这个是inteval分区,high_value是TO_DATE(' 2013-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA

    试一下删除分区:

    SQL> alter table t drop partition P201304;
     
    Table altered.
     
     将P201304分区删除,这个分区的数据也会同时删除。

    SQL> select partition_name, interval, high_value from dba_tab_partitions where table_owner=user and table_name = 'T' order by partition_position;
     
    PARTITION_NAME                 INT HIGH_VALUE
    ------------------------------ --- -------------------------------------------------------------------------------------
    P201303                        NO  TO_DATE(' 2013-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    P201305                        NO  TO_DATE(' 2013-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    SYS_P41                        YES TO_DATE(' 2013-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    SQL> alter table t drop partition P201305;
    alter table t drop partition P201305
                                 *
    ERROR at line 1:
    ORA-14758: Last partition in the range section cannot be dropped
    删除P201305的时候出错,提示最后一个range分区无法删除

    那怎么删除这个分区?

    步骤如下:

    --先执行一下set interval(),使得interval的值都为NO
    SQL> alter table t set interval (NUMTOYMINTERVAL(1,'month'));
     
    Table altered.
     
    SQL> select partition_name, interval, high_value from dba_tab_partitions where table_owner=user and table_name = 'T' order by partition_position;
     
    PARTITION_NAME                 INT HIGH_VALUE
    ------------------------------ --- -------------------------------------------------------------------------------------
    P201303                        NO  TO_DATE(' 2013-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    P201305                        NO  TO_DATE(' 2013-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    SYS_P41                        NO  TO_DATE(' 2013-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    --再删除的时间就没有问题了
    SQL> alter table t drop partition P201305;
    Table altered.
    --验证删除成功!
    SQL> select partition_name, interval, high_value from dba_tab_partitions where table_owner=user and table_name = 'T' order by partition_position;
    PARTITION_NAME                 INT HIGH_VALUE
    ------------------------------ --- -------------------------------------------------------------------------------------
    P201303                        NO  TO_DATE(' 2013-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
    SYS_P41                        NO  TO_DATE(' 2013-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA

    统计审计基表AUD$UNIFIED ,不允许直接更改,且默认是按月分区。
    通过以下 DBMS_AUDIT_MGMT 更改分区为1天

    1. BEGIN
    2. DBMS_AUDIT_MGMT.ALTER_PARTITION_INTERVAL(
    3. interval_number => 1,
    4. interval_frequency => 'DAY');
    5. END;
    6. /
    7. SQL> select table_name,partition_name,INTERVAL,HIGH_VALUE,HIGH_VALUE_LENGTH from dba_tab_partitions where table_name='AUD$UNIFIED';
    8. TABLE_NAME PARTITION_NAME INT HIGH_VALUE HIGH_VALUE_LENGTH
    9. ------------------------------ ------------------------------ --- ---------------------------------------- -----------------
    10. AUD$UNIFIED SYS_P306 NO TIMESTAMP' 2017-09-01 00:00:00' 31
    11. SYS@ORCLCDB>col owner for a20
    12. SYS@ORCLCDB>col INTERVAL for a50
    13. SYS@ORCLCDB>select owner,table_name,interval,partitioning_type,partition_count,def_tablespace_name from dba_part_Tables where owner='AUDSYS';
    14. OWNER TABLE_NAME INTERVAL PARTITIONING_TYPE PARTITION_COUNT DEF_TABLESPACE_NAME
    15. -------------------- -------------------- -------------------------------------------------- ------------------ --------------- ------------------------------------------------------------
    16. AUDSYS AUD$UNIFIED NUMTODSINTERVAL(1, 'DAY')

     

    (五)关于间隔分区的常见问题

    (5.1)如何将现有普通表转换为间隔分区

    可以使用如下命令将现有的范围分区表转换为间隔分区表,注意,仅仅支持范围分区表:

    ALTER TABLE <table_name> SET INTERVAL <number or interval expression>;

    (5.2)如何为现有表设置新的间隔

    可以使用如下命令修改间隔,该操作不会使index不可用:

    ALTER TABLE <table_name> SET INTERVAL(interval express);

    (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   

    (5.5)使用DBMS_METADATA.GET_DDL检索表时,为什么缺少系统生成的间隔分区?

    "DBMS_METADATA.GET_DDL"只提供用户手段创建的分区,而不提供系统自动生成的分区。以下为测试例子:

    1. SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','INTERVAL_NUMBER_TABLE01','LIJIAMAN') FROM DUAL;
    2. 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,使用需要谨慎。


    (七)间隔分区的利弊思考

    好处:间隔分区通过系统自动创建分区,减少了DBA的日常运维工作,避免了ORA-14400这类错误,每年年终不需要为下一年手动创建分区,想想还是挺开心的;

    坏处:因为系统自动创建分区名称,我们无法通过分区名称来判断数据的存放位置,增加了后期的维护难度。举个例子,如果是DBA手动维护,假设表的分区”part_201901“存储的就是2019年1月的数据,假如我们想要删除1月份的数据,直接删除该分区即可,如果数据库里面有500个类似的表,直接写批量脚本”ALTER TABLE DROP PARTITION part_201901“就将全部表的1月份的数据删除了,但是对于系统自动创建的分区,在不同的表里面,2019年1月的数据对应的分区名不同,自然无法使用脚本批量删除,即使有脚本,也非常麻烦。

  • 相关阅读:
    Redis的分布式锁问题(十)最强分布式锁工具:Redisson
    Dubbo-聊聊Dubbo协议
    纳米软件介绍什么是LABVIEW?
    常用稳压电源---DCDC和LDO
    CUDA学习笔记6——事件计时
    [学习笔记]ARXML - Data Format
    python基于django仓库进销存管理系统 计算机毕业设计
    Spring基础:依赖注入
    leetcode:1941. 检查是否所有字符出现次数相同(python3解法)
    Linux目录
  • 原文地址:https://blog.csdn.net/jnrjian/article/details/133614841