sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur migrerar man en befintlig Postgres-tabell till en partitionerad tabell så transparent som möjligt?

I Postgres 10 introducerades "Deklarativ partitionering", vilket kan avlasta dig från en hel del arbete som att generera triggers eller regler med enorma if/else-satser som omdirigerar till rätt tabell. Postgres kan göra detta automatiskt nu. Låt oss börja med migreringen:

  1. Byt namn på den gamla tabellen och skapa en ny partitionerad tabell

    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);
    

Detta torde knappast kräva någon förklaring. Den gamla tabellen döps om (efter datamigrering tar vi bort den) och vi får en huvudtabell för vår partition som i princip är densamma som vår ursprungliga tabell, men utan index)

  1. Skapa en funktion som kan generera nya partitioner när vi behöver dem:

    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;
    

Detta kommer väl till pass senare.

  1. Skapa en vy som i princip bara delegerar till vårt huvudbord:

    create or replace view myTable as select * from myTable_master;
    
  2. Skapa regel så att när vi infogar i regeln kommer vi inte bara att uppdatera den partitionerade tabellen, utan också skapa en ny partition om det behövs:

    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)
        );
    

Naturligtvis, om du också behöver update och delete , du behöver också en regel för dem som ska vara rättfram.

  1. Migrera faktiskt den gamla tabellen:

    -- 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;
    

Nu är migreringen av tabellen klar utan att det behövdes veta hur många partitioner som behövs och även vyn myTable kommer att vara helt transparent. Du kan enkelt infoga och välja från den tabellen som tidigare, men du kan få prestandafördelar med partitionering.

Observera att vyn endast behövs eftersom en partitionerad tabell inte kan ha radutlösare. Om du kan komma överens med att ringa createPartitionIfNotExists manuellt närhelst det behövs från din kod, du behöver inte vyn och alla dess regler. I det här fallet måste du lägga till partitionerna också manuellt under migreringen:

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. Exekveringsordning för villkor i SQL 'where'-sats

  2. Hur infogar man en fil i MySQL-databasen?

  3. Hur man ignorerar Duplicate Key-fel i T-SQL (SQL-server)

  4. Returnerar strängarray och använd den på AutoCompleteTextview