PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Datenstrukturdesign für die Unterstützung der Datenbankreplikation

Nun, das erste, was ich tun würde, ist, das eklige String-Parsing überall fallen zu lassen und es durch native PostgreSQL-Typen zu ersetzen. So speichern Sie den Replikationsstatus für jeden Datensatz ähnlich Ihrer aktuellen Lösung:

CREATE TYPE replication_status AS ENUM (
  'no_action',
  'replicate_record',
  'record_replicated',
  'error_1',
  'error_2',
  'error_3'
  );
ALTER TABLE t ADD COLUMN rep_status_array replication_status[];

Dies kostet Sie etwas mehr Speicherplatz – Enum-Werte sind 4 Bytes statt 1 und Arrays haben etwas Overhead. Indem Sie der Datenbank Ihre Konzepte beibringen, anstatt sie zu verstecken, können Sie Dinge schreiben wie:

-- find all records that need to be replicated to host 4
SELECT * FROM t WHERE rep_status_array[4] = 'replicate_record';

-- find all records that contain any error status
SELECT * FROM t WHERE rep_status_array &&
  ARRAY['error_1', 'error_2', 'error_3']::replication_status[];

Sie können einen GIN-Index direkt auf rep_status_array setzen wenn das Ihrem Anwendungsfall hilft, aber es ist besser, sich Ihre Abfragen anzusehen und Indizes speziell für das zu erstellen, was Sie verwenden:

CREATE INDEX t_replication_host_4_key ON t ((rep_status_array[4]));
CREATE INDEX t_replication_error_key ON t (id)
  WHERE rep_status_array && ARRAY['error_1', 'error_2', 'error_3']::replication_status[];

Angesichts von 200 Tabellen wäre ich jedoch versucht, dies in eine einzige Replikationsstatustabelle aufzuteilen – entweder eine Zeile mit einem Array von Status oder eine Zeile pro Host, je nachdem, wie der Rest der Replikationslogik funktioniert. Ich würde immer noch diese Aufzählung verwenden:

CREATE TABLE adhoc_replication (
  record_id bigint not null,
  table_oid oid not null,
  host_id integer not null,
  replication_status status not null default 'no_action',
  primary key (record_id,table_oid,host_id)
  );

PostgreSQL weist jeder Tabelle intern eine OID zu (versuchen Sie SELECT *, tableoid FROM t LIMIT 1 ), bei dem es sich um einen bequemen stabilen numerischen Bezeichner innerhalb eines einzelnen Datenbanksystems handelt. Anders ausgedrückt, es ändert sich, wenn die Tabelle gelöscht und neu erstellt wird (was passieren kann, wenn Sie z. B. die Datenbank sichern und wiederherstellen), und aus demselben Grund ist es sehr wahrscheinlich zwischen Entwicklung und Produktion unterschiedlich. Wenn Sie möchten, dass diese Situationen beim Hinzufügen oder Umbenennen einer Tabelle im Austausch für Unterbrechungen funktionieren, verwenden Sie eine Enumeration anstelle einer OID.

Die Verwendung einer einzigen Tabelle für die gesamte Replikation würde es Ihnen ermöglichen, Trigger und Abfragen und dergleichen einfach wiederzuverwenden und die meiste Replikationslogik von den replizierten Daten zu entkoppeln. Es ermöglicht Ihnen auch, basierend auf dem Status für einen bestimmten Host alle Ihre Ursprungstabellen abzufragen, indem Sie auf einen einzelnen Index verweisen, was wichtig sein könnte.

Was die Tabellengröße betrifft, kann PostgreSQL definitiv 10 Millionen Zeilen in derselben Tabelle verarbeiten. Wenn Sie sich für eine dedizierte replikationsbezogene Tabelle entschieden haben, können Sie immer partitionieren pro Wirt. (Die Partitionierung nach Tabelle macht für mich wenig Sinn; es scheint schlimmer zu sein, als den Replikationsstatus in jeder Upstream-Zeile zu speichern.) Welche Art der Partitionierung geeignet ist oder ob sie überhaupt angemessen ist, hängt ganz davon ab, welche Art von Fragen Sie Ihrer Datenbank stellen möchten, und welche Art von Aktivität auf den Basistabellen stattfindet. (Partitionieren bedeutet, statt einiger großer Blobs viele kleinere Blobs zu verwalten und möglicherweise auf viele kleinere Blobs zuzugreifen, um eine einzelne Operation auszuführen.) Es ist wirklich eine Frage der Wahl, wann Ihre Festplatte suchen soll.