web-dev-qa-db-ja.com

Oracle 11gでの通常のリストパーティションから参照パーティションへの切り替え

メインの親テーブルと、通常のパーティション分割が設定された複数の子テーブルがあり、すべての子テーブルでパーティション列が繰り返されています。参照パーティションに切り替えたい(Oracle 11g)。私の子テーブルには現在2つのパーティションがあり、どちらも削除して参照パーティションに置き換える必要があります。

現在、最後のパーティションを削除し、ALTERコマンドを使用して新しい参照パーティションを追加するという問題に直面しています。

テーブルを削除してデータを失うことができないので、これを行う方法はありますか?パーティション列に作成されたインデックスがあります。

私が使用しているクエリ:

ALTER TABLE CHILD_TABLE_1
    DROP PARTITIONS part1, part2
    UPDATE INDEXES; --- here only one partition was dropped

ALTER TABLE CHILD_TABLE_1 ADD PARTITION BY REFERENCE (foreign_key_with_parent);

これはエラーになります

エラー:ORA-00902:無効なデータ型SQLState:42000エラーコード:902

5

パーティション交換を使用するのは、はるかに速く、はるかにクールですが、はるかに複雑な方法です。

私はそれだけを使うでしょう

  • 十分なデータがある(たとえば、100万行以上、または1 GBを超えるパーティション)
  • 同じ構造と十分な量のデータを備えたテストデータベース/スキーマがあり、簡単に再作成できます(私の経験では、スクリプトは通常、2回目の試行後にのみ正しく機能します)
  • 移行スクリプトを開発してテストする時間がある

最小限のテーブル、データ、および列を持つモックアップが与えられた場合:

CREATE TABLE parent(id NUMBER PRIMARY KEY, par NUMBER, c VARCHAR2(30)
) PARTITION BY LIST (par) (
  PARTITION p1 VALUES(1,3,5,7,9), 
  PARTITION p2 VALUES(0,2,4,6,8));

CREATE TABLE child(id REFERENCES parent, par NUMBER, t VARCHAR2(30)
) PARTITION BY LIST (par) (
  PARTITION p1 VALUES(1,3,5,7,9), 
  PARTITION p2 VALUES(0,2,4,6,8));      

INSERT INTO parent(id,par,c)
SELECT object_id, mod(object_id,10) as par, object_name FROM all_objects;

INSERT INTO child(id,par,t)   
SELECT object_id, mod(object_id,10) as par, object_type FROM all_objects;

最初に、データを保留する保持テーブルを作成します。

CREATE TABLE temp_parent_p1 AS SELECT * FROM parent WHERE 1=0;
CREATE TABLE temp_parent_p2 AS SELECT * FROM parent WHERE 1=0;
CREATE TABLE temp_child_p1  AS SELECT * FROM child  WHERE 1=0;
CREATE TABLE temp_child_p2  AS SELECT * FROM child  WHERE 1=0;

次に、最初に子、次に親の順にデータを交換します。

ALTER TABLE child  EXCHANGE PARTITION p1 WITH TABLE temp_child_p1;
ALTER TABLE child  EXCHANGE PARTITION p2 WITH TABLE temp_child_p2;
DROP  TABLE child;
ALTER TABLE parent EXCHANGE PARTITION p1 WITH TABLE temp_parent_p1;
ALTER TABLE parent EXCHANGE PARTITION p2 WITH TABLE temp_parent_p2;
DROP  TABLE parent;

次に、新しいテーブル構造を再作成します。

CREATE TABLE parent(id NUMBER PRIMARY KEY, par NUMBER, c VARCHAR2(30)
) PARTITION BY LIST (par) (
  PARTITION p1 VALUES(1,3,5,7,9), 
  PARTITION p2 VALUES(0,2,4,6,8));

CREATE TABLE child(id REFERENCES parent, par NUMBER, c VARCHAR2(30)
) PARTITION BY LIST (par) (
  PARTITION p1 VALUES(1,3,5,7,9), 
  PARTITION p2 VALUES(0,2,4,6,8));

次に、パークされたパーティションにインデックスを付ける必要があります。列と制約は、新しいテーブルとまったく同じ構造である必要があります(ただし、名前については心配しないでください)。次に、データを元に戻すことができます。

ALTER TABLE temp_parent_p1 ADD PRIMARY KEY (id);
ALTER TABLE temp_parent_p2 ADD PRIMARY KEY (id);
ALTER TABLE parent EXCHANGE PARTITION p1 WITH TABLE temp_parent_p1;
ALTER TABLE parent EXCHANGE PARTITION p2 WITH TABLE temp_parent_p2;

親が完了したら、子を元に戻すことができます。

ALTER TABLE temp_child_p1 ADD FOREIGN KEY (id) REFERENCES parent(id);
ALTER TABLE temp_child_p2 ADD FOREIGN KEY (id) REFERENCES parent(id);
ALTER TABLE child  EXCHANGE PARTITION p1 WITH TABLE temp_child_p1;
ALTER TABLE child  EXCHANGE PARTITION p2 WITH TABLE temp_child_p2;

その後のクリーンアップの少し:

BEGIN 
  DBMS_STATS.GATHER_TABLE_STATS(NULL,'parent');
  DBMS_STATS.GATHER_TABLE_STATS(NULL,'child');
END;
/
DROP TABLE temp_parent_p1;
DROP TABLE temp_parent_p2;
DROP TABLE temp_child_p1;
DROP TABLE temp_child_p2;
1
wolφi

別のフォーラムで、レンジパーティションからリファレンスへの変換について質問しました。

https://community.Oracle.com/message/14807741

答えは:DBMS_REDEFINITION

新しいテーブルに移行する必要がある余分なスペースと少なくともいくつかの制約(fk)があるので、これは最良のオプションです。

DBMS_REDEFINITIONは、面倒な作業(移動制約)をすべて実行します。

0
Michael Kutz

従来のアプローチは

  1. 古い子テーブルと親テーブルの名前を変更する
  2. 参照によるパーティションで新しいテーブルを作成します(これは、参照によるパーティションで必要なため、親テーブルの主キーと子テーブルの外部キーを含みます)。
  3. 古いテーブルから新しいテーブルにデータをコピーする
  4. 他のインデックスと制約を作成する
  5. 新しいテーブルの統計を収集する
  6. 古いテーブルを削除する
0
wolφi