sql >> Databasteknik >  >> RDS >> PostgreSQL

Datastrukturdesign för databasreplikeringsstöd

Tja, det första jag skulle göra är att släppa den svåra strängtolkningen överallt och ersätta den med inhemska PostgreSQL-typer. Så här lagrar du replikeringsstatusen på varje post som liknar din nuvarande lösning:

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

Detta kostar dig lite mer lagringsutrymme -- enumvärden är 4 byte istället för 1 och arrayer har en viss overhead. Men genom att lära databasen dina begrepp istället för att dölja dem kan du skriva saker som:

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

Du kan sätta ett GIN-index direkt på rep_status_array om det hjälper ditt användningsfall, men det är bättre att titta på dina frågor och skapa index specifikt för det du använder:

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

Som sagt, med tanke på 200 tabeller, skulle jag vara frestad att dela upp detta i en enda replikeringsstatustabell -- antingen en rad med en rad statuser eller en rad per värd, beroende på hur resten av replikeringslogiken fungerar. Jag skulle fortfarande använda den uppräkningen:

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 tilldelar internt varje tabell en OID (försök med SELECT *, tableoid FROM t LIMIT 1 ), vilket är en bekväm stabil numerisk identifierare inom ett enda databassystem. Med andra ord ändras den om tabellen släpps och återskapas (vilket kan hända om du t.ex. dumpar och återställer databasen), och av samma anledning är det mycket troligt att det skiljer sig mellan utveckling och produktion. Om du hellre vill att dessa situationer ska fungera i utbyte mot att de går sönder när du lägger till eller byter namn på en tabell, använd en uppräkning istället för en OID.

Att använda en enda tabell för all replikering skulle tillåta dig att enkelt återanvända triggers och frågor och sådant, och frikoppla den mesta replikeringslogiken från data som den replikerar. Det låter dig också fråga baserat på status för en given värd i alla dina ursprungstabeller genom att referera till ett enda index, vilket kan vara viktigt.

När det gäller tabellstorlek kan PostgreSQL definitivt hantera 10 miljoner rader i samma tabell. Om du använde en dedikerad replikeringsrelaterad tabell kunde du alltid partitionera per värd. (Att partitionera efter tabell är inte meningsfullt för mig; det verkar värre än att lagra replikeringsstatus på varje uppströmsrad.) Vilket sätt att partitionera eller om det överhuvudtaget är lämpligt beror helt på vilken typ av frågor du tänker ställa din databas, och vilken typ av aktivitet som händer på bastabellerna. (Partitionering innebär att behålla många mindre blobbar istället för några få stora, och potentiellt komma åt många mindre blobbar för att utföra en enda operation.) Det är verkligen en fråga om att välja när du vill att din disk ska hända.



  1. Hur får man de två första tecknen i en sträng i en orakelfråga?

  2. Hur lägger man till primärnyckel för automatisk ökning baserat på en kolumnordning?

  3. Hur man använder REPLACE i SQL

  4. Det går inte att infoga Varchar2-data med en lagrad procedur med tabelltyp som IN-parameter