非分区表进行分区的方法


非分区表进行成分区的方法,From Oracle support:(文档 ID 1985005.1)


 A. 通过 Export/import 方法

 B. 通过 Insert with a subquery 方法

 C. 通过 Partition Exchange 方法

 D. 通过 DBMS_REDEFINITION 方法



A. 通过 Export/import 方法


这种方法的实现是先 export 一个非分区表,创建一个新的分区表,然后 import 数据到新创建的分区表中。


1) Export 您的非分区表:


$ exp usr/pswd tables=numbers file=exp.dmp

2) Drop 掉该非分区表:


SQL> drop table numbers;

3) 重新创建该表成为一个分区表:


SQL> create table numbers (qty number(3), name varchar2(15)) partition by range (qty)(partition p1 values less than (501),

partition p2 values less than (maxvalue));

4) 通过 import 的 ignore=y 方式来还原备份的数据:


$ imp usr/pswd file=exp.dmp ignore=y

ignore=y 语句会让 import 忽略掉表的创建,直接加载所有数据。


如果使用 Data Pump export/import(expdp/impdp)您可以采用 impdp 的 table_exists_action 选项,例如 table_exists_action = APPEND 或者 table_exists_action = REPLACE。


您也可以参考 Note 552424.1 Export/Import DataPump Parameter ACCESS_METHOD - How to Enforce a Method of Loading and Unloading Data?


B. 通过 Insert with a subquery 方法


1) 创建一个分区表:


SQL> create table partbl (qty number(3), name varchar2(15)) partition by range (qty) (partition p1 values less than (501),partition p2 values less than (maxvalue));


2) 将原来非分区表中的数据通过子查询 insert 到新创建的分区表中:


SQL> insert into partbl (qty, name) select * from origtbl;


3) 如果您想让新建的分区表与原表名相同,那么 drop 掉原来的非分区表然后重命名新表:


SQL> drop table origtbl;

SQL> alter table partbl rename to origtbl;

您可以通过 direct path insert 和利用并行来改善 insert 的性能。如下的例子演示了如何实现并且如何从执行计划中来验证。


传统的 insert


SQL> insert into partbl (qty, name) select * from origtbl;

--------------------------------------------

| Id  | Operation                | Name    |

--------------------------------------------

|   0 | INSERT STATEMENT         |         |

|   1 |  LOAD TABLE CONVENTIONAL |         |

|   2 |   TABLE ACCESS FULL      | ORIGTBL |

--------------------------------------------

Direct load insert 方式


SQL> insert /*+APPEND*/ into partbl (qty, name) select * from origtbl;

--------------------------------------

| Id  | Operation          | Name    |

--------------------------------------

|   0 | INSERT STATEMENT   |         |

|   1 |  LOAD AS SELECT    |         |

|   2 |   TABLE ACCESS FULL| ORIGTBL |

--------------------------------------

Direct load insert 并且在查询部分开启并行


SQL> insert /*+APPEND PARALLEL*/ into partbl (qty, name) select * from origtbl;

------------------------------------------

| Id  | Operation             | Name     |

------------------------------------------

|   0 | INSERT STATEMENT      |          |

|   1 |  LOAD AS SELECT       |          |

|   2 |   PX COORDINATOR      |          |

|   3 |    PX SEND QC (RANDOM)| :TQ10000 |

|   4 |     PX BLOCK ITERATOR |          |

|*  5 |      TABLE ACCESS FULL| ORIGTBL  |

------------------------------------------

注意以上执行计划中 LOAD AS SELECT 在 PX COORDINATOR 的上面。


Direct load insert 并且在查询部分和 insert 部分都开启并行


SQL>alter session enable parallel dml;

SQL> insert /*+APPEND PARALLEL*/ into partbl (qty, name) select * from origtbl;

------------------------------------------

| Id  | Operation             | Name     |

------------------------------------------

|   0 | INSERT STATEMENT      |          |

|   1 |  PX COORDINATOR       |          |

|   2 |   PX SEND QC (RANDOM) | :TQ10000 |

|   3 |    LOAD AS SELECT     |          |

|   4 |     PX BLOCK ITERATOR |          |

|*  5 |      TABLE ACCESS FULL| ORIGTBL  |

------------------------------------------

注意在以上执行计划中 LOAD AS SELECT 在 PX COORDINATOR 的下面。


另外一种可选的方式是直接通过 select 来创建新的分区表:一次性创建新的分区表并且加载数据。

执行计划同时显示 direct path load 并且 dml 以及 select 部分全部并行。


SQL>alter session enable parallel dml;

SQL> create table partbl (qty, name) partition by range (qty) (partition p1 values less than (501),partition p2 values less than (maxvalue))

  2  as select /*+PARALLEL*/ * from origtbl;

-------------------------------------------

| Id  | Operation              | Name     |

-------------------------------------------

|   0 | CREATE TABLE STATEMENT |          |

|   1 |  PX COORDINATOR        |          |

|   2 |   PX SEND QC (RANDOM)  | :TQ10000 |

|   3 |    LOAD AS SELECT      |          |

|   4 |     PX BLOCK ITERATOR  |          |

|*  5 |      TABLE ACCESS FULL | ORIGTBL  |

-------------------------------------------

C. 通过 Partition Exchange 方法


ALTER TABLE EXCHANGE PARTITION 可以通过交换数据和索引 segment 来将一个分区(或子分区)转换成一个非分区表,也可以将一个非分区表转换成一个分区表的分区(或子分区)。 除了需要更新索引以外,ALTER TABLE ... EXCHANGE PARTITION 命令是一个字典操作不需要数据移动。更多关于此方法的信息参见 Oracle 联机文档(比如 11.2)和 Note 198120.1。


此方法简要步骤如下:


1) 根据所需的分区来创建新的分区表

2) 保持需要交换的非分区表与分区表的分区有相同的结构,并且确保您需要交换的非分区表具有您想要交换的内容

3) 执行:Alter table exchange partition partition_name with table exchange table



注意在交换过程中,所有交换的数据必须满足分区表的分区定义,否则如下错误将抛出:ORA-14099: all rows in table do not qualify for specified partition.


这是因为默认情况下分区交换是有校验的。



例子(基于 SCOTT 示例 schema)

---------


本例创建了与分区表 p_emp 的分区相同结构的交换表。


SQL> CREATE TABLE p_emp

2 (sal NUMBER(7,2))

3 PARTITION BY RANGE(sal)

4 (partition emp_p1 VALUES LESS THAN (2000),

5 partition emp_p2 VALUES LESS THAN (4000));


Table created.



SQL> SELECT * FROM emp;


     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO

---------- ---------- --------- ---------- --------- ---------- ---------- ----------

      7369 SMITH      CLERK           7902 17-DEC-80        800                    20

      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30

      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30

      7566 JONES      MANAGER         7839 02-APR-81       2975                    20

      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30

      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30

      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10

      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20

      7839 KING       PRESIDENT            17-NOV-81       5000                    10

      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30

      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20

      7900 JAMES      CLERK           7698 03-DEC-81        950                    30

      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20

      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10


14 rows selected.


SQL> CREATE TABLE exchtab1 as SELECT sal FROM emp WHERE sal<2000;


Table created.


SQL> CREATE TABLE exchtab2 as SELECT sal FROM emp WHERE sal BETWEEN 2000 AND 3999;


Table created.

--- 官方这里应该是有错误的,应该将where后的sal(加粗部分) 改成 * 才能实现与原emp表一致的分区----


SQL> alter table p_emp exchange partition emp_p1 with table exchtab1;


Table altered.


SQL> alter table p_emp exchange partition emp_p2 with table exchtab2;


Table altered.

D. 通过 DBMS_REDEFINITION 方法

(文档 ID 1481558.1)

PURPOSE


This Note has been written to provide some volume details and timings for the process

to convert a normal table to a partition table using the DBMS_REDEFINITION package.


The note will also include details of objects used by the process (Fast Refresh) and how

these become populated during the procedure.


The procedure is broken down into the following sections:


1.  Create the Partition Table structure required, known as the Interim table.

2.  Execute DBMS_REDEFINITION.can_redef_table...

3.  Execute DBMS_REDEFINITION.start_redef_table...

4.  Execute DBMS_REDEFINITION.sync_interim_table...

5.  Execute DBMS_REDEFINITION.finish_redef_table...

6.  Drop the interim table.


DETAILS


Worked example under 11.2.0.3



--   Initial setup of table to be partitioned.


CREATE TABLE unpar_table (

  a NUMBER, y number,

  name VARCHAR2(100), date_used date);


alter table unpar_table ADD (CONSTRAINT unpar_table_pk PRIMARY KEY (a,y));


--  load table with 1,000,000 rows


begin

        for i in 1 .. 1000

        loop

            for j in 1 .. 1000

            loop

insert into unpar_table values ( i, j, dbms_random.random, sysdate-j );

            end loop;

        end loop;

end;

   /

commit;


PL/SQL procedure successfully completed.

Elapsed: 00:01:56.90


Commit complete.


SQL> EXEC DBMS_STATS.gather_table_stats(user, 'unpar_table', cascade => TRUE);


SELECT   num_rows FROM user_tables WHERE table_name = 'UNPAR_TABLE';

  NUM_ROWS

----------

   1000000


Elapsed: 00:00:00.01


SQL> CREATE TABLE par_table (

    a NUMBER, y number,

    name VARCHAR2(100),date_used DATE)

   PARTITION BY RANGE (date_used)

    (PARTITION unpar_table_12 VALUES LESS THAN (TO_DATE('10/07/2012', 'DD/MM/YYYY')),

     PARTITION unpar_table_15 VALUES LESS THAN (TO_DATE('15/07/2012', 'DD/MM/YYYY')),

     PARTITION unpar_table_MX VALUES LESS THAN (MAXVALUE));


SQL> EXEC Dbms_Redefinition.can_redef_table(USER, 'unpar_table');


PL/SQL procedure successfully completed.


Elapsed: 00:00:00.07


--  This procedure (DBMS_REDEFINITION.start_redef_table) creates a materialized view based on a CTAS, as we can see below with 

--  the PREBUILT container table.

 

SQL> BEGIN

DBMS_REDEFINITION.start_redef_table(

uname => USER,

orig_table => 'unpar_table',

int_table => 'par_table');

END;

/


PL/SQL procedure successfully completed.


Elapsed: 00:00:06.69


select mview_name,container_name, build_mode from user_mviews;

MVIEW_NAME                     CONTAINER_NAME                 BUILD_MOD

------------------------------ ------------------------------ ---------

PAR_TABLE                      PAR_TABLE                      PREBUILT


Elapsed: 00:00:00.13

 

--  Insert 1000 rows into the master table while the DBMS_REDEF is active.

--  This will use the mview log created by the DBMS_REDEFINITION.start_redef_table.

--  Check the MLOG$_<table name> table to confirm these online updates have been recorded.


SQL> begin

        for i in 1001 .. 1010

        loop

            for j in 1001 .. 1100

            loop

insert into unpar_table values ( i, j, dbms_random.random, sysdate-j );

            end loop;

        end loop;

    end;

   /

commit;


Elapsed: 00:00:00.24


SQL> select count(*) from MLOG$_UNPAR_TABLE;


  COUNT(*)

----------

      1000

 

--  Run the dbms_redefinition.sync_interim_table to populate the new table structure (implements a MVIEW FAST REFRESH)

--  with the online updates.  This will purge the mview log of each record applied.

--  This can be run many times and should be, before we do the Finish_REDEF_TABLE.


SQL> BEGIN

dbms_redefinition.sync_interim_table(

uname => USER,

orig_table => 'unpar_table',

int_table => 'par_table');

END;


PL/SQL procedure successfully completed.


Elapsed: 00:00:02.01


ALTER TABLE par_table ADD (CONSTRAINT par_table_pk2 PRIMARY KEY (a,y)); 



EXEC DBMS_STATS.gather_table_stats(USER, 'par_table', cascade => TRUE);


--  Finish_redef_table swaps the table names so the interim table becomes the original table name.

--  After completing this step, the original table is redefined with the attributes and data of the interim table. 

--  The original table is locked briefly during this procedure.


BEGIN

dbms_redefinition.finish_redef_table(

uname => USER,

orig_table => 'unpar_table',

int_table => 'par_table');

END;

/

 

--  Note, both tables will now be synchronised.


select count(*) from par_table ;

  COUNT(*)

----------

   1001000


select count(*) from unpar_table ;

  COUNT(*)

----------

   1001000

 

--  Dictionary views to confirm the change of strructure of our original table "UNPAR_TABLE".


SELECT partitioned FROM user_tables WHERE table_name = 'UNPAR_TABLE';


PAR

---

YES


SELECT partition_name, num_rows FROM user_tab_partitions WHERE table_name = 'UNPAR_TABLE';



PARTITION_NAME                   NUM_ROWS

------------------------------ ----------

UNPAR_TABLE_12                     980000

UNPAR_TABLE_15                       5000

UNPAR_TABLE_MX                      16000

 

--  At this point the Interim table can be dropped.


drop TABLE par_table  cascade constraints;

 


Note for previous versions.



For tests done under 11.1.0.7 the timings for the sync_interim_table where the interim table is large (1,000,000 in our case) the timings for this are considerably longer.  This was not reviewed in depth, but initial investigation looks like the mview refresh for DBMS_REDEFINITION has been updated during the MERGE cycle.


example:


11.1.0.7 

SYNC of 1000 rows --         Elapsed: 00:01:36.30     (1.5 minutes)


你可能感兴趣的:(非分区表进行分区的方法)