1 单表转分区表说明
在Oracle 10g的官方手册里有提到,当单表的大小超过2G的时候,就建议使用分区表。 当然这个数字在在之后版本的官方文档中删除了。
在10g 和 11g中,单表转分区表,我们有四种方法:
- Export/import method(导入导出)
- Insert with a subquery method(插入子查询的方法)
- Partition exchange method(交换分区法)
- DBMS_REDEFINITION(在线重定义)
在Oracle 12.2 版本之后,Oracle 支持直接通过ALTER TABLE .. MODIFY
转换非分区表为分区表。
关于Oracle 12 架构的版本区别和特性,可以参考我之前的博客:
从生命周期的角度来谈谈Oracle 软件的版本(12c/18c/19c/20c/21c)问题
https://www.cndba.cn/dave/article/107944Oracle 12.2 家族的补丁 RU 和 RUR 说明
https://www.cndba.cn/dave/article/4063《Oracle 18c 必须掌握的新特性》
https://www.cndba.cn/dave/article/3453
官网对VLDB的说明可以参考:
https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/index.html
当然,在Oracle 12.2 家族的架构下,还是支持在线重定义的,只是补充了在直接MODIFY 的方法, 关于这两种方法的说明,可以参考官网:
4.6.1 Using Online Redefinition to Partition Collection Tables
https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/evolve-nopartition-table.html#GUID-5C0F8D12-DDDF-42AB-B644-1880156832BC
4.6.2 Converting a Non-Partitioned Table to a Partitioned Table
https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/evolve-nopartition-table.html#GUID-5FDB7D59-DD05-40E4-8AB4-AF82EA0D0FE5
2 操作示例
我们先看官网的示例demo:
ALTER TABLE employees_convert MODIFY
PARTITION BY RANGE (employee_id) INTERVAL (100)
( PARTITION P1 VALUES LESS THAN (100),
PARTITION P2 VALUES LESS THAN (500)
) ONLINE
UPDATE INDEXES
( IDX1_SALARY LOCAL,
IDX2_EMP_ID GLOBAL PARTITION BY RANGE (employee_id)
( PARTITION IP1 VALUES LESS THAN (MAXVALUE))
);
注意,在生产环境,建议在非业务高峰期,采用非ONLINE 方式进行转换。 虽然ONLINE 方式不影响DML操作,但还是不建议采用这种方式,毕竟Oracle 当初在线重建索引是有历史教训在那的。
创建测试表:
[dave@www.cndba.cn ~]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Tue Apr 11 10:13:56 2023
Version 19.18.0.0.0
Copyright (c) 1982, 2022, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.18.0.0.0
SQL> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 DAVE READ WRITE NO
SQL> alter session set container=dave;
Session altered.
SQL> CREATE TABLE CNDBA(ID NUMBER,WEBSITE VARCHAR2(30));
Table created.
SQL>
插入测试数据:
SQL> declare
2 v1 number;
3 begin
4 for i in 1..300000
5 loop
6 execute immediate 'insert into CNDBA values(:v1,''www.cndba.cn'')' using i;
7 end loop;
8 commit;
9 end;
10 /
PL/SQL procedure successfully completed.
SQL>
添加主键索引:
SQL> alter table cndba add constraint pk_cndba primary key(id);
Table altered.
SQL> col index_name for a15
SQL> col status for a15
SQL> select index_name,status from user_indexes where index_name in ('PK_CNDBA');
INDEX_NAME STATUS
--------------- ---------------
PK_CNDBA VALID
SQL>
在线转分区:
SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
TO_CHAR(SYSDATE,'YYYY-MM-DDHH24:MI:SS')
---------------------------------------------------------
2023-04-11 10:41:20
SQL> ALTER TABLE CNDBA MODIFY
2 PARTITION BY RANGE (ID)
3 ( PARTITION P1 VALUES LESS THAN (100000),
4 PARTITION P2 VALUES LESS THAN (200000),
5 PARTITION P3 values less than (maxvalue)
6 ) UPDATE INDEXES parallel 8;
Table altered.
SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
TO_CHAR(SYSDATE,'YYYY-MM-DDHH24:MI:SS')
---------------------------------------------------------
2023-04-11 10:41:37
SQL>
此时索引已经变成了分区索引,注意并行度查看:
SQL> col degree for a15
SQL> select index_name,status,degree from user_indexes where index_name in ('PK_CNDBA');
INDEX_NAME STATUS DEGREE
--------------- --------------- ---------------
PK_CNDBA N/A 1
SQL> col PARTITION_NAME for a15
SQL> select index_name,partition_name, status,GLOBAL_STATS from dba_ind_partitions where index_name='PK_CNDBA';
INDEX_NAME PARTITION_NAME STATUS GLOBAL_ST
--------------- --------------- --------------- ---------
PK_CNDBA P1 USABLE NO
PK_CNDBA P2 USABLE NO
PK_CNDBA P3 USABLE NO
查看表分区:
SQL> COL TABLE_NAME FOR A15
SQL> select TABLE_NAME,PARTITION_NAME from dba_tab_partitions where table_name='CNDBA';
TABLE_NAME PARTITION_NAME
--------------- ---------------
CNDBA P1
CNDBA P2
CNDBA P3
SQL>
这里要注意,对于生产环境,不建议使用ONLINE,另外当表很大,且表上索引较多的情况下,转换时间也会受索引影响。