Oracle-分区表解读(下)

简介: Oracle-分区表解读(下)

Oracle 11g-Interval Partitioning


数据库管理员日常要做的一件重复而无聊的工作 比如每隔一天要生成新的24个分区,用以存储第二天的数据。而在11g中这项工作可以交由Oracle自动完成了,基于Range和List的Interval Partitioning分区类型登场。


在 11g 里的 Interval 创建,这种方法对没有写全的分区会自动创建。 比如我

这里只写了 1 月日期,如果插入的数据有其他月份的,会自动生成对应的分区。

CREATE TABLE TB_INTERVAL 
PARTITION BY RANGE (time_col) 
INTERVAL(NUMTOYMINTERVAL(1, 'month')) 
(PARTITION P0 VALUES LESS THAN (TO_DATE('1-1-2016', 'dd-mm-yyyy'))); 

指定需要Oracle自动创建分区的间隔时间,上面这个例子是1个月,然后至少创建一个基本分区,上面这个例子是在2016-1-1之前的所有数据都在P0分区中,以后每个月的数据都会存放在Oracle自动创建的一个新分区中。

select table_name,partition_name from user_tab_partitions where
table_name='TB_INTERVAL';
select count(*) from TB_INTERVAL partition (p1);

创建按月分区的分区表

  1. 创建分区表
/* Formatted on 2010/6/10 20:21:12 (QP5 v5.115.810.9015) */
create table intervalpart (c1 number, c3 date)
partition by range (c3)
interval ( numtoyminterval (1, 'month') )
(partition part1
values less than (to_date ('01/12/2010', 'mm/dd/yyyy')),
partition part2
values less than (to_date ('02/12/2010', 'mm/dd/yyyy'))
)


注意: 如果在建 Interval 分区表是没有把所有的分区写完成,在插入相关数据后会自动生成分区

2. 查看现在表的分区:

SQL> select table_name,partition_name from user_tab_partitions where
table_name='INTERVALPART';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVALPART PART1
INTERVALPART PART2


  1. 插入测试数据:
SQL> begin
2 for i in 0 .. 11 loop
3 insert into intervalpart
values(i,add_months(to_date('2010-1-1','yyyy-mm-dd'),i));
4 end loop ;
5 commit;
6 end;
7 /


PL/SQL 过程已成功完成。

补充: add_months() 函数获取前一个月或者下一个月的月份, 参数中 负数 代

表 往前, 正数 代表 往后。

–上一个月

select to_char(add_months(trunc(sysdate),-1),'yyyymm') from dual;

–下一个月

select to_char(add_months(trunc(sysdate),1),'yyyymm') from dual;
  1. 观察自动创建的分区:
SQL> select table_name,partition_name from user_tab_partitions where
table_name='INTERVALPART';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
INTERVALPART PART1
INTERVALPART PART2
INTERVALPART SYS_P22
INTERVALPART SYS_P23
INTERVALPART SYS_P24
INTERVALPART SYS_P25
INTERVALPART SYS_P26
INTERVALPART SYS_P27
INTERVALPART SYS_P28
INTERVALPART SYS_P29
INTERVALPART SYS_P30
INTERVALPART SYS_P31

已选择 12 行。

5. 查看分区内容:

SQL> select * from INTERVALPART;
C1 C3
--------- ----------
1 2010-01-01
0 2010-01-01
1 2010-02-01
2 2010-03-01
3 2010-04-01
4 2010-05-01
5 2010-06-01
6 2010-07-01
7 2010-08-01
8 2010-09-01
9 2010-10-01
10 2010-11-01
11 2010-12-01
已选择 13 行。
SQL> select * from INTERVALPART partition(part1);
C1 C3
--------- ----------
1 2010-01-01
0 2010-01-01
SQL> select * from INTERVALPART partition(part2);
C1 C3
--------- ----------
1 2010-02-01


创建一个以天为间隔的分区表

  1. 创建分区表:
SQL> create table dave
2 (
3 id number,
4 dt date
5 )
6 partition by range (dt)
7 INTERVAL (NUMTODSINTERVAL(1,'day'))
8 (
9 partition p100101 values less than (to_date('2010-01-01','yyyy-mm-dd'))
10 );


  1. 查看表分区:
SQL> select table_name,partition_name from user_tab_partitions where table_name='DAVE';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
DAVE P100101


  1. 插入测试数据:
SQL> begin
2 for i in 1 .. 12 loop
3 insert into dave values(i,trunc(to_date('2010-1-1','yyyy-mm-dd')+i));
4 end loop;
5 commit;
6 end;
7 /

PL/SQL 过程已成功完成。

4. 观察自动创建的分区:

SQL> select table_name,partition_name from user_tab_partitions where
table_name='DAVE';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
DAVE P100101
DAVE SYS_P32
DAVE SYS_P33
DAVE SYS_P34
DAVE SYS_P35
DAVE SYS_P36
DAVE SYS_P37
DAVE SYS_P38
DAVE SYS_P39
DAVE SYS_P40
DAVE SYS_P41
DAVE SYS_P42
DAVE SYS_P43


已选择 13 行。

5. 查看分区内容:

SQL> select * from dave partition(SYS_P32);
ID DT
---------- ----------
1 2010-01-02
SQL> select * from dave partition(SYS_P33);
ID DT
-------- ----------
2 2010-01-03
SQL> select * from dave partition(SYS_P34);
ID DT
-------- ----------
3 2010-01-04
SQL> select * from dave;
ID DT
-------- ----------
1 2010-01-02
2 2010-01-03
3 2010-01-04
4 2010-01-05
5 2010-01-06
6 2010-01-07
7 2010-01-08
8 2010-01-09
9 2010-01-10
10 2010-01-11
11 2010-01-12
12 2010-01-13
已选择 12 行。


System Partitioning


系统分区,在这个新的类型中,我们不需要指定任何分区键,数据会进入哪个分区完全由应用程序决定,实际上也就是由SQL来决定,终于,我们在Insert语句中可以指定插入哪个分区了。

假设我们创建了下面这张分区表,注意,没有指定任何分区键:

CREATE TABLE systab (c1 integer, c2 integer) 
PARTITION BY SYSTEM 
( 
PARTITION p1 TABLESPACE tbs_1, 
PARTITION p2 TABLESPACE tbs_2, 
PARTITION p3 TABLESPACE tbs_3, 
PARTITION p4 TABLESPACE tbs_4 
); 

现在由SQL语句来指定插入哪个分区:

– 数据插入p1分区

INSERT INTO systab PARTITION (p1) VALUES (4,5);


– 数据插入第2个分区,也就是p2分区

INSERT INTO systab PARTITION (2) VALUES (7,8);

– 为了实现绑定变量,用pno变量来代替实际分区号,以避免过度解析

INSERT INTO systab PARTITION (:pno) VALUES (9,10);


由于System Partitioning的特殊性,所以很明显,这种类型的分区将不支持Partition Split操作,也不支持create table as select操作。


12C 对表分区维护的增强


Oracle Database 12c对表分区变化比较多,共分为下面几点


1.在线移动分区:通过MOVE ONLINE关键字实现在线分区移动。移动过程中,对表和被移动的分区可以执行查询操作,


DML语句以及分区的创建和维护操作。整个移动过程对用户来说是透明的。


2.多个分区同时操作:可以对多个分区同时进行维护操作,如将一年的12个分区合并到一个新的分区中,或者将一个分区


分成多个分区。可以通过FOR语句指定操作的每个语句,对于RANGE分区而言,也可以通过TO来指定处理分区的范围。


多个分区操作自动并行完成。


3.INTERVAL-REFERENCE分区:把11g的interval分区和reference分区结合,这样主表自动增加一个分区后,所有字表,


孙子表·····重重孙子表上都会自动随着外界列数据增加,自动创建新的分区。


4.TRUNCATE和EXCHANGE分区及子分区。五分是TRUNCATE还是EXCHANGE分区,在主表上执行,都可以级联的作用在字表,


孙子吧·····重重孙子表上同时执行。对于TRUNCATE而言,所有表的TRUNACATE操作在同一个事务中,如果中途失败,

会回滚到之前的状态。通过关键字CASCADE实现。


5.异步全局索引维护:对于非常大的分区表而言,UPDATE GLOBAL INDEX不再是痛苦。Oracle可以实现了异步维护的


功能,即使是几亿条的记录的全局索引,在分区维护操作,比如DROP或TRUNCATE后,仍然是VALID状态,索引不会失效,


不过索引的状态是包含OBSOLETE数据,当维护操作完成,索引状态恢复。


6.部分本地和全局索引:Oracle的所有可以在分区级别定义。无论全局索引还是本地所有都可以在分区表的部分分区


上建立,其他分区上则没有所有。当通过所有列访问全表数据时,Oracle通过UNION ALL实现,一部分通过索引扫描,

另一部分通过全分区扫描。这可以减少对历史数据的索引量,增强了灵活性。


具体例子:

1)添加多个新分区:


在12c之前,一次只能添加一个新分区到一个已存在的分区表。在12c中只需要一条单独的ALTER TABLE ADD PARTITION


命令就可以添加N个新分区。

 ALTER TABLE EMP_PART ADD PARTITION
 PARTITION P4 VALUES LESS THAN(35000)
 PARTITION P5 VALUES LESS THAN(40000)

同样,只要MAXVALUE分区不存在,可以添加多个新分区到一个列表和系统分区表

2)删除、截断多个分区/子分区

通过在此之前,一次只能删除/截断一个分区。12c中通过ALTER TABLE table_name {TRUNCAT|DROP} PARTITIONS

 ALTER TABLE EMP_PART DROP PARTITIONS P4,P5;
 ALTER TABLE EMP_PART TRUNCATE PARTITIONS P4,P5;

要保持索引更新,使用UPDATE INDEXES或UPDATE GLOBAL INDEXES语句。

 ALTER TABLE EMP_PART DROP PARTITIONS P4,P5 UPDATE GLOBAL INDEXES;
 ALTER TABLE EMP_PART TRUNCATE PARTITIONS P4,P5 UPDATE GLOBAL INDEXES;

如果没有使用UPDATE GLOBAL INDEXES更新索引,也可以通过查询ORPHANED_ENTRIES字段找出是否有索引包含过期的条目

3)将单个分区分割为多个新分区

在此之前是无法单个命令完成这个操作的。

 ALTER TABLE EMP_PART SPLIT PARTITIONS p_max INTO
 (PARTITION P4 VALUES LESS THAN (30000),
 PARTITION P5 VALUES LESS THAN(40000),
 PARTITION P_MAX);


4)将多个分区合并为一个分区

ALTER TABLE EMP_PART MERGE PARTITIONS P2,P3,P4 INTO PARTITION P_MERGE;


如果是连续分区,可以通过TO来

ALTER TABLE EMP_PART MERGE PARTITIONS P2 TO P4 INTO PARTITION P_MERGE;


普通表转分区表方法


将普通表转换成分区表有 4 种方法:

1. Export/import method

2. Insert with a subquery method

3. Partition exchange method

4. DBMS_REDEFINITION

详情参考

How to Partition a Non-partitioned Table [ID 1070693.6]

或者

oracle将普通表改为分区表


表分区的相关操作


1.添加分区


添加新的分区有 2 中情况:

( 1)原分区里边界是 maxvalue 或者 default。 这种情况下,我们需要把边界分区 drop 掉,加上新分区后,在添加上新的分区。 或者采用 split,对边界分区进行拆分。

( 2)没有边界分区的。 这种情况下,直接添加分区就可以了。


以边界分区添加新分区示例:

( 1)分区表和索引的信息如下:

SQL> create table custaddr
2 (
3 id varchar2(15 byte) not null,
4 areacode varchar2(4 byte)
5 )
6 partition by list (areacode)
7 (
8 partition t_list556 values ('556') tablespace icd_service,
9 partition p_other values (default)tablespace icd_service
10 );

表已创建。

SQL> create index ix_custaddr_id on custaddr(id)
2 local (
3 partition t_list556 tablespace icd_service,
4 partition p_other tablespace icd_service
5 );


索引已创建。

( 2)插入几条测试数据:

SQL> insert into custaddr values('1','556');
已创建 1 行。
SQL> insert into custaddr values('2','551');
已创建 1 行。
SQL> insert into custaddr values('3','555');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select * from custaddr;
ID AREA
--------------- ----
1 556
2 551
3 555
SQL> select * from custaddr partition(t_list556);
ID AREA
--------------- ----
1 556
SQL>


( 3)删除 default 分区

sql> alter table custaddr drop partition p_other;
表已更改。
sql> select table_name,partition_name from user_tab_partitions where
table_name='CUSTADDR';
table_name partition_name
------------------------------ ------------------------------
custaddr t_list556


( 4)添加新分区

SQL> alter table custaddr add partition t_list551 values('551') tablespace icd_service;
表已更改。
SQL> select table_name,partition_name from user_tab_partitions where
table_name='CUSTADDR';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
CUSTADDR T_LIST556
CUSTADDR T_LIST551


( 5)添加 default 分区

SQL> alter table custaddr add partition p_other values (default) tablespace
icd_service;
表已更改。
SQL> select table_name,partition_name from user_tab_partitions where
table_name='CUSTADDR';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
CUSTADDR T_LIST556
CUSTADDR T_LIST551
CUSTADDR P_OTHER

( 6)对于局部索引, oracle 会自动增加一个局部分区索引。验证一下:

sql> select owner,index_name,table_name,partitioning_type from dba_part_indexes
where index_name='ix_custaddr_id';
owner index_name table_name
---------------------- ------------------------------ ------------------
icd ix_custaddr_id custaddr
sql> select index_owner,index_name,partition_name from dba_ind_partitions where
index_name='ix_custaddr_id';
index_owner index_name partition_name
------------------------------ ------------------------------ ------------------
icd ix_custaddr_id p_other
icd ix_custaddr_id t_list551
icd ix_custaddr_id t_list556


分区索引自动创建了。

用 split方法示例

sql> alter table custaddr split partition p_other values('552') into (partition t_list552
tablespace icd_service, partition p_other tablespace icd_service);
表已更改。


–注意values(‘552’),如果是 Range 类型的,使用 at, List 使用 Values。

SQL> select table_name,partition_name from user_tab_partitions where
table_name='CUSTADDR';
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
CUSTADDR T_LIST556
CUSTADDR T_LIST551
CUSTADDR T_LIST552
CUSTADDR P_OTHER
SQL> select index_owner,index_name,partition_name from dba_ind_partitions
where index_name='IX_CUSTADDR_ID';
index_owner index_name partition_name
------------------------------ ------------------------------ ------------------
icd ix_custaddr_id p_other
icd ix_custaddr_id t_list551
icd ix_custaddr_id t_list552
icd ix_custaddr_id t_list556


注意:分区表会自动维护局部分区索引。全局索引会失效,需要进行 rebuild。

2.删除分区

alter table T_TRACK drop partition p_2005_04;


3.添加子分区

alter table T_TRACK
        modify partition P_2005_01
        add subpartition P_2005_01_P1017 values('P1017');


4.删除子分区

alter table T_TRACK drop subpartition p_2005_01_p1017;


5.截断一个分区表中的一个分区的数据:

  alter table sales3  truncate partition sp1
           --这种方式会使全局分区索引无效
  alter table sales3 truncate partition sp1 update indexes
          --这种方式全局分区索引不会无效


说明:

Truncate 相对 delete 操作很快,数据仓库中的大量数据的批量数据加载可能

会有用到; 截断分区同样会自动维护局部分区索引,同时会使全局索引 unusable,需要重建


6.截断分区表的子分区

alter table comp truncate subpartition sub1


7.截断带有约束的分区表

 a、禁用约束
          alter table sales disable constraint dname_sales1
        b、截断分区
          alter table sales truncate partitoin dec
        c、启用约束
          alter table sales enable constraint dname_sales1


8.查看一个表是不是分区表

  select table_name,partitioned from user_tables;
        TABLE_NAME                     PAR
        ------------------------------ ---
        DEPT                           NO
        DEPT3                          YES

9.将一个表的分区从一个表空间移动到另一个表空间

 a、查看分区在哪个表空间
          SELECT TABLE_OWNER,TABLE_NAME,PARTITION_NAME,TABLESPACE_NAME,
          SUBPARTITION_COUNT
          FROM DBA_TAB_PARTITIONS WHERE TABLE_OWNER='SCOTT';
        b、移动分区
          alter table sales move partiton sp1 tablespace tp;
        c、检查是否移动成功
          SELECT TABLE_OWNER,TABLE_NAME,PARTITION_NAME,TABLESPACE_NAME,
          SUBPARTITION_COUNT
          FROM DBA_TAB_PARTITIONS WHERE TABLE_OWNER='SCOTT';
        移动表空间后,要重建索引,否则索引会变得无效
        alter index xxx rebuild


注意: 分区移动会自动维护局部分区索引, oracle 不会自动维护全局索引,所以需要我们重新 rebuild 分区索引,具体需要 rebuild 哪些索引,可以通过

dba_part_indexes,dba_ind_partitions 去判断

SQL> Select index_name,status From user_indexes Where
table_name='CUSTADDR';
INDEX_NAME STATUS
------------------------------ --------
IX_CUSTADDR_ID N/A


10.合并分区:


相邻的分区可以 merge 为一个分区,新分区的下边界为原来边界值较低的分区,上边界为原来边界值较高的分区, 原先的局部索引相应也会合并,全局索引会失效,需要 rebuild。

alter table sales3 merge partitons sp1,sp3 into partition sp3


合并后的分区名,不能是边界值较低的那个

11.与分区表相关的数据字典视图:

        DBA_TAB_PARTITIONS
        DBA_IND_PARTITIONS
        DBA_TAB_SUBPARTITIONS
        DBA_IND_SUBPARTITIONS


相关文章
|
6月前
|
Kubernetes Oracle 关系型数据库
实时计算 Flink版产品使用合集之是否支持 Oracle 分区表
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
6月前
|
SQL Oracle 关系型数据库
Oracle-使用切片删除的方式清理非分区表中的超巨数据
Oracle-使用切片删除的方式清理非分区表中的超巨数据
106 1
|
6月前
|
Oracle 关系型数据库 索引
Oracle-维护存在主键的分区表时的注意事项
Oracle-维护存在主键的分区表时的注意事项
159 0
|
6月前
|
SQL 存储 Oracle
Oracle-分区表解读
Oracle-分区表解读
216 0
|
消息中间件 Oracle 关系型数据库
Flink CDC确实支持Oracle分区表的CDC
Flink CDC确实支持Oracle分区表的CDC
236 1
|
消息中间件 Oracle 关系型数据库
Flink CDC确实支持Oracle分区表的CDC,但是在配置时需要特别注意。以下是一些可能的解决方案
Flink CDC确实支持Oracle分区表的CDC,但是在配置时需要特别注意。以下是一些可能的解决方案
132 1
|
SQL 存储 Oracle
Oracle-分区表解读(上)
Oracle-分区表解读
135 0
|
SQL 数据采集 Oracle
怎样使用oracle分区表
怎样使用oracle分区表
168 0