1

データベース内のすべてのパーティション テーブルで 60 日未満の高い値を持つすべてのパーティションを削除する SQL スクリプトを 11g で作成しました。

DECLARE
   TNAME      VARCHAR2 (300);
   PNAME      VARCHAR2 (300);
   HIGHVAL    VARCHAR2 (3000);
   POSITION   SMALLINT;
   VAL        LONG;

   CURSOR C1
   IS
      SELECT TABLE_NAME, PARTITION_NAME, PARTITION_POSITION, HIGH_VALUE
        FROM USER_TAB_PARTITIONS
       WHERE TABLE_NAME NOT LIKE '%$%'
         AND TABLE_NAME NOT LIKE 'BIN%';
BEGIN
   OPEN C1;

   LOOP
      FETCH C1
       INTO TNAME, PNAME, POSITION, VAL;

      HIGHVAL := VAL;
      EXIT WHEN C1%NOTFOUND;

      IF TO_DATE (SUBSTR (HIGHVAL, 10, 11), 'RRRR-MM-DD') <
                                                          TRUNC (SYSDATE)
                                                          - 60
      THEN
         IF POSITION = 1
         THEN
            DBMS_OUTPUT.PUT_LINE ('ALTER TABLE ' || TNAME
                                  || ' SET INTERVAL();'
                                 );
         END IF;

         DBMS_OUTPUT.PUT_LINE (   'ALTER TABLE '
                               || TNAME
                               || ' DROP PARTITION '
                               || PNAME
                               || ' UPDATE GLOBAL INDEXES PARALLEL 2;'||CHR(10)
                               || '--DROPPED'
                               || '--'
                               || TO_DATE (SUBSTR (HIGHVAL, 10, 11),
                                           'RRRR-MM-DD'
                                          )
                              );

         IF POSITION = 1
         THEN
            DBMS_OUTPUT.PUT_LINE
                                (   'ALTER TABLE '
                                 || TNAME
                                 || ' SET INTERVAL(NUMTODSINTERVAL(1,''DAY''));'
                                );
         END IF;
      END IF;
   END LOOP;

   COMMIT;

   CLOSE C1;
END;
/

生成された SQL テキストを実行しています

これが正しく、改善の余地があるかどうかアドバイスをお願いします???

4

1 に答える 1

1

いくつかのヒント:

  • これは暗黙のカーソルに最適な場所であるため、手動で変数を宣言したり、フェッチしたり、開いたり閉じたりする必要はありません...
  • クエリで高い値をフィルター処理します。早いほど良い
  • 出力されたものを手動で実行する代わりに、EXECUTE IMMEDIATE を使用して変更を適用します。
  • すべてDDLなので、コミットする必要はありません

コード:

BEGIN
  FOR p IN (SELECT TABLE_NAME, PARTITION_NAME, PARTITION_POSITION, HIGH_VALUE
            FROM USER_TAB_PARTITIONS
            WHERE TABLE_NAME NOT LIKE '%$%'
            AND TABLE_NAME NOT LIKE 'BIN%'
            AND TO_DATE (SUBSTR (HIGH_VALUE, 10, 11), 'RRRR-MM-DD') < TRUNC (SYSDATE) - 60)
  LOOP
    IF p.PARTITION_POSITION = 1
    THEN
      EXECUTE IMMEDIATE 'ALTER TABLE ' || p.TABLE_NAME || ' SET INTERVAL()';
    END IF;

    EXECUTE IMMEDIATE 'ALTER TABLE ' || p.TABLE_NAME
                   || 'DROP PARTITION ' || p.PARTITION_NAME
                   || ' UPDATE GLOBAL INDEXES PARALLEL 2';

    IF p.PARTITION_POSITION = 1
    THEN
      EXECUTE IMMEDIATE 'ALTER TABLE ' || p.TABLE_NAME
                     || ' SET INTERVAL(NUMTODSINTERVAL(1,''DAY''));';
    END IF;
  END LOOP;
END;
/

そして、いくつかの警告:

  • UPDATE GLOBAL INDEXES に注意してください。IOT テーブルでは機能しません (使用している場合)。 (これは私が間違っていました)
  • リセット/設定間隔に注意してください。原則として、最後の非インターバル パーティションは削除できません。これがポジション1になると推測するのは危険です。user_tab_partitions.interval フラグに依存することをお勧めします。
于 2013-11-13T22:02:26.387 に答える