PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak przeprowadzić migrację istniejącej tabeli Postgres do tabeli partycjonowanej tak przejrzyście, jak to możliwe?

W Postgresie 10 wprowadzono „Deklaratywne partycjonowanie”, które może odciążyć Cię od wielu prac, takich jak generowanie wyzwalaczy lub reguł z ogromnymi instrukcjami if/else przekierowującymi do właściwej tabeli. Postgres może to teraz zrobić automatycznie. Zacznijmy od migracji:

  1. Zmień nazwę starej tabeli i utwórz nową tabelę podzieloną na partycje

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

Nie powinno to wymagać żadnego wyjaśnienia. Nazwa starej tabeli zostaje zmieniona (po migracji danych usuniemy ją) i otrzymujemy główną tabelę dla naszej partycji, która jest zasadniczo taka sama jak nasza oryginalna tabela, ale bez indeksów)

  1. Utwórz funkcję, która może generować nowe partycje, gdy ich potrzebujemy:

    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;
    

Przyda się to później.

  1. Utwórz widok, który po prostu deleguje do naszej tabeli głównej:

    create or replace view myTable as select * from myTable_master;
    
  2. Utwórz regułę, aby po wstawieniu do reguły nie tylko aktualizować partycjonowaną tabelę, ale także tworzyć nową partycję, jeśli zajdzie taka potrzeba:

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

Oczywiście, jeśli potrzebujesz także update i delete , potrzebujesz również reguły dla tych, które powinny być proste.

  1. Właściwie migruj starą tabelę:

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

Teraz migracja tabeli jest kompletna bez potrzeby znajomości liczby potrzebnych partycji oraz widoku myTable będzie absolutnie przejrzysta. Możesz po prostu wstawiać i wybierać z tej tabeli, jak poprzednio, ale możesz uzyskać korzyści w zakresie wydajności dzięki partycjonowaniu.

Należy zauważyć, że widok jest potrzebny tylko, ponieważ tabela podzielona na partycje nie może mieć wyzwalaczy wierszy. Jeśli możesz się dogadać z wywołaniem createPartitionIfNotExists ręcznie w dowolnym momencie z kodu, nie potrzebujesz widoku i wszystkich jego reguł. W takim przypadku musisz dodać partycje również ręcznie podczas migracji:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak uzyskać rejestrowanie czasu wykonania zapytania przez psycopg2?

  2. Najlepsze nowe funkcje w PostgreSQL 14

  3. Jak zaokrąglić średnią do 2 miejsc po przecinku w PostgreSQL?

  4. Przewodnik po użyciu pgBouncera w PostgreSQL

  5. Czy istnieje sposób na zdefiniowanie nazwanej stałej w zapytaniu PostgreSQL?