sql >> データベース >  >> RDS >> PostgreSQL

既存のPostgresテーブルを可能な限り透過的にパーティションテーブルに移行するにはどうすればよいですか?

    Postgres 10では、「宣言型パーティショニング」が導入されました。これにより、トリガーやルールを生成して、正しいテーブルにリダイレクトする巨大なif/elseステートメントを使用するなどの多くの作業を軽減できます。 Postgresはこれを自動的に実行できるようになりました。移行から始めましょう:

    1. 古いテーブルの名前を変更し、新しいパーティションテーブルを作成します

      alter table myTable rename to myTable_old;
      
      create table myTable_master(
          forDate date not null,
          key2 int not null,
          value int not null
      ) partition by range (forDate);
      

    これはほとんど説明を必要としないはずです。古いテーブルの名前が変更され(データ移行後に削除されます)、パーティションのマスターテーブルが取得されます。これは、基本的に元のテーブルと同じですが、インデックスはありません)

    1. 必要に応じて新しいパーティションを生成できる関数を作成します。

      create function createPartitionIfNotExists(forDate date) returns void
      as $body$
      declare monthStart date := date_trunc('month', forDate);
          declare monthEndExclusive date := monthStart + interval '1 month';
          -- We infer the name of the table from the date that it should contain
          -- E.g. a date in June 2005 should be int the table mytable_200506:
          declare tableName text := 'mytable_' || to_char(forDate, 'YYYYmm');
      begin
          -- Check if the table we need for the supplied date exists.
          -- If it does not exist...:
          if to_regclass(tableName) is null then
              -- Generate a new table that acts as a partition for mytable:
              execute format('create table %I partition of myTable_master for values from (%L) to (%L)', tableName, monthStart, monthEndExclusive);
              -- Unfortunatelly Postgres forces us to define index for each table individually:
              execute format('create unique index on %I (forDate, key2)', tableName);
          end if;
      end;
      $body$ language plpgsql;
      

    これは後で便利になります。

    1. 基本的にマスターテーブルに委任するだけのビューを作成します:

      create or replace view myTable as select * from myTable_master;
      
    2. ルールを作成して、ルールに挿入するときに、パーティションテーブルを更新するだけでなく、必要に応じて新しいパーティションを作成するようにします。

      create or replace rule autoCall_createPartitionIfNotExists as on insert
          to myTable
          do instead (
              select createPartitionIfNotExists(NEW.forDate);
              insert into myTable_master (forDate, key2, value) values (NEW.forDate, NEW.key2, NEW.value)
          );
      

    もちろん、updateも必要な場合 およびdelete 、簡単なルールも必要です。

    1. 実際に古いテーブルを移行します:

      -- Finally copy the data to our new partitioned table
      insert into myTable (forDate, key2, value) select * from myTable_old;
      
      -- And get rid of the old table
      drop table myTable_old;
      

    これで、テーブルの移行が完了しました。必要なパーティションの数と、ビューmyTableを知る必要はありませんでした。 完全に透明になります。以前と同じように、そのテーブルから簡単に挿入して選択できますが、パーティション化によってパフォーマンスが向上する可能性があります。

    パーティションテーブルには行トリガーを含めることができないため、ビューのみが必要であることに注意してください。 createPartitionIfNotExistsの呼び出しにうまく対応できる場合 コードから必要なときに手動で、ビューとそのすべてのルールは必要ありません。この場合、移行中にパーティションを手動で追加する必要があります:

    do
    $$
    declare rec record;
    begin
        -- Loop through all months that exist so far...
        for rec in select distinct date_trunc('month', forDate)::date yearmonth from myTable_old loop
            -- ... and create a partition for them
            perform createPartitionIfNotExists(rec.yearmonth);
        end loop;
    end
    $$;
    


    1. PostgreSQLで大規模な非ブロッキング更新を行うにはどうすればよいですか?

    2. Oracleで文字列の一部を削除する方法

    3. SQLクロス結合

    4. SQL Serverで先行ゼロをトリミングするためのより良い手法はありますか?