Dela via


Distribuera och ändra tabeller i Azure Cosmos DB för PostgreSQL

GÄLLER FÖR: Azure Cosmos DB for PostgreSQL (drivs av Citus-databastillägget till PostgreSQL)

Distribuera tabeller

Om du vill skapa en distribuerad tabell måste du först definiera tabellschemat. För att göra det kan du definiera en tabell med instruktionen CREATE TABLE på samma sätt som med en vanlig PostgreSQL-tabell.

CREATE TABLE github_events
(
    event_id bigint,
    event_type text,
    event_public boolean,
    repo_id bigint,
    payload jsonb,
    repo jsonb,
    actor jsonb,
    org jsonb,
    created_at timestamp
);

Sedan kan du använda funktionen create_distributed_table() för att ange tabelldistributionskolumnen och skapa arbetsshards.

SELECT create_distributed_table('github_events', 'repo_id');

Funktionsanropet informerar Azure Cosmos DB för PostgreSQL om att den github_events tabellen ska distribueras i kolumnen repo_id (genom att hasha kolumnvärdet).

Det skapar totalt 32 shards som standard, där varje shard äger en del av ett hash-utrymme och replikeras baserat på standardvärdet citus.shard_replication_factor konfiguration. De shardrepliker som skapas i arbetaren har samma tabellschema, index och villkorsdefinitioner som tabellen i koordinatorn. När replikerna har skapats sparar funktionen alla distribuerade metadata på koordinatorn.

Varje skapad shard tilldelas ett unikt shard-ID och alla dess repliker har samma shard-ID. Shards representeras på arbetsnoden som vanliga PostgreSQL-tabeller med namnet "tablename_shardid" där tabellnamnet är namnet på den distribuerade tabellen och shard-ID är det unika ID som tilldelats. Du kan ansluta till arbetspostgres-instanserna för att visa eller köra kommandon på enskilda shards.

Nu är du redo att infoga data i den distribuerade tabellen och köra frågor på den. Du kan också lära dig mer om UDF som används i det här avsnittet i tabellen och Shard DDL-referensen .

Referenstabeller

Metoden ovan distribuerar tabeller till flera vågräta shards. En annan möjlighet är att distribuera tabeller till en enda shard och replikera fragmentet till varje arbetsnod. Tabeller som distribueras på det här sättet kallas referenstabeller. De används för att lagra data som måste användas ofta av flera noder i ett kluster.

Vanliga kandidater för referenstabeller är:

  • Mindre tabeller som behöver kopplas till större distribuerade tabeller.
  • Tabeller i appar med flera klientorganisationer som saknar en klientorganisations-ID-kolumn eller som inte är associerade med en klientorganisation. (Eller, under migreringen, även för vissa tabeller som är associerade med en klient.)
  • Tabeller som behöver unika begränsningar i flera kolumner och som är tillräckligt små.

Anta till exempel att en e-handelsplats för flera innehavare måste beräkna moms för transaktioner i någon av dess butiker. Skatteinformation är inte specifik för någon klientorganisation. Det är vettigt att placera den i en delad tabell. En usa-centrerad referenstabell kan se ut så här:

-- a reference table

CREATE TABLE states (
  code char(2) PRIMARY KEY,
  full_name text NOT NULL,
  general_sales_tax numeric(4,3)
);

-- distribute it to all workers

SELECT create_reference_table('states');

Nu kan frågor som en beräkningsskatt för en kundvagn anslutas states till tabellen utan nätverkskostnader och kan lägga till en sekundärnyckel i delstatskoden för bättre validering.

Förutom att distribuera en tabell som en enda replikerad shard markerar create_reference_table UDF den som en referenstabell i metadatatabellerna i Azure Cosmos DB for PostgreSQL. Azure Cosmos DB for PostgreSQL utför automatiskt tvåfasincheckningar (2PC) för ändringar i tabeller som markerats på det här sättet, vilket ger starka konsekvensgarantier.

Ett annat exempel på hur du använder referenstabeller finns i självstudien om databas för flera klientorganisationer.

Distribuera koordinatordata

Om en befintlig PostgreSQL-databas konverteras till koordinatornoden för ett kluster kan data i dess tabeller distribueras effektivt och med minimalt avbrott i ett program.

Funktionen create_distributed_table som beskrevs tidigare fungerar på både tomma och icke-tomma tabeller, och för det senare distribuerar den automatiskt tabellrader i hela klustret. Du vet om det kopierar data genom att meddelandet "OBS! Kopierar data från en lokal tabell..." Till exempel:

CREATE TABLE series AS SELECT i FROM generate_series(1,1000000) i;
SELECT create_distributed_table('series', 'i');
NOTICE:  Copying data from local table...
 create_distributed_table
 --------------------------

 (1 row)

Skrivningar i tabellen blockeras medan data migreras och väntande skrivningar hanteras som distribuerade frågor när funktionen checkas in. (Om funktionen misslyckas blir frågorna lokala igen.) Läsningar kan fortsätta som vanligt och distribueras frågor när funktionen checkas in.

När du distribuerar tabellerna A och B, där A har en sekundärnyckel till B, distribuerar du nyckelmåltabellen B först. Om du gör det i fel ordning orsakas ett fel:

ERROR:  cannot create foreign key constraint
DETAIL:  Referenced table must be a distributed table or a reference table.

Om det inte går att distribuera i rätt ordning släpper du sekundärnycklarna, distribuerar tabellerna och återskapar sekundärnycklarna.

När du migrerar data från en extern databas, till exempel från Amazon RDS till Azure Cosmos DB for PostgreSQL, skapar du först azure Cosmos DB for PostgreSQL-distribuerade tabeller via create_distributed_tableoch kopierar sedan data till tabellen. Om du kopierar till distribuerade tabeller får du inte slut på utrymme på koordinatornoden.

Samlokalisera tabeller

Samlokalisering innebär att placera relaterad information på samma datorer. Det möjliggör effektiva frågor samtidigt som du drar nytta av den horisontella skalbarheten för hela datauppsättningen. Mer information finns i colocation.

Tabeller samallokeras i grupper. Om du vill styra en tabells grupptilldelning manuellt använder du den valfria colocate_with parametern create_distributed_table. Om du inte bryr dig om en tabells samlokalisering utelämnar du den här parametern. Det är som standard värdet 'default', som grupperar tabellen med andra standardsamplaceringstabeller med samma distributionskolumntyp, shardantal och replikeringsfaktor. Om du vill bryta eller uppdatera den här implicita samlokaliseringen kan du använda update_distributed_table_colocation().

-- these tables are implicitly co-located by using the same
-- distribution column type and shard count with the default
-- co-location group

SELECT create_distributed_table('A', 'some_int_col');
SELECT create_distributed_table('B', 'other_int_col');

När en ny tabell inte är relaterad till andra i den implicita samlokaliseringsgruppen anger du colocated_with => 'none'.

-- not co-located with other tables

SELECT create_distributed_table('A', 'foo', colocate_with => 'none');

Genom att dela upp orelaterade tabeller i sina egna samlokaliseringsgrupper förbättras prestanda för horisontell ombalansering , eftersom shards i samma grupp måste flyttas tillsammans.

När tabeller verkligen är relaterade (till exempel när de kommer att anslutas) kan det vara klokt att uttryckligen samplacera dem. Vinsterna med lämplig samlokalisering är viktigare än eventuella ombalanseringskostnader.

Om du uttryckligen vill samplacera flera tabeller distribuerar du en och placerar sedan de andra i dess samlokaliseringsgrupp. Till exempel:

-- distribute stores
SELECT create_distributed_table('stores', 'store_id');

-- add to the same group as stores
SELECT create_distributed_table('orders', 'store_id', colocate_with => 'stores');
SELECT create_distributed_table('products', 'store_id', colocate_with => 'stores');

Information om samlokaliseringsgrupper lagras i tabellen pg_dist_colocation , medan pg_dist_partition visar vilka tabeller som har tilldelats till vilka grupper.

Ta bort tabeller

Du kan använda standardkommandot PostgreSQL DROP TABLE för att ta bort dina distribuerade tabeller. Precis som med vanliga tabeller tar DROP TABLE bort alla index, regler, utlösare och begränsningar som finns för måltabellen. Dessutom släpper den även fragmenten på arbetsnoderna och rensar deras metadata.

DROP TABLE github_events;

Ändra tabeller

Azure Cosmos DB for PostgreSQL sprider automatiskt många typer av DDL-instruktioner. Om du ändrar en distribuerad tabell på koordinatornoden uppdateras även shards för arbetarna. Andra DDL-instruktioner kräver manuell spridning och vissa andra är förbjudna, till exempel alla som skulle ändra en distributionskolumn. Om du försöker köra DDL som inte är berättigad till automatisk spridning genereras ett fel och tabellerna på koordinatornoden lämnas oförändrade.

Här är en referens till de kategorier av DDL-instruktioner som sprids.

Lägga till/ändra kolumner

Azure Cosmos DB for PostgreSQL sprider de flesta ALTER TABLE-kommandon automatiskt. Att lägga till kolumner eller ändra deras standardvärden fungerar som i en PostgreSQL-databas med en dator:

-- Adding a column

ALTER TABLE products ADD COLUMN description text;

-- Changing default value

ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;

Betydande ändringar i en befintlig kolumn som att byta namn på den eller ändra dess datatyp är också bra. Datatypen för distributionskolumnen kan dock inte ändras. Den här kolumnen bestämmer hur tabelldata distribueras via klustret och att ändra dess datatyp skulle kräva att data flyttas.

Om du försöker göra det uppstår ett fel:

-- assumining store_id is the distribution column
-- for products, and that it has type integer

ALTER TABLE products
ALTER COLUMN store_id TYPE text;

/*
ERROR:  XX000: cannot execute ALTER TABLE command involving partition column
LOCATION:  ErrorIfUnsupportedAlterTableStmt, multi_utility.c:2150
*/

Lägga till/ta bort begränsningar

Med Hjälp av Azure Cosmos DB for PostgreSQL kan du fortsätta att njuta av säkerheten för en relationsdatabas, inklusive databasbegränsningar (se PostgreSQL-dokumenten). På grund av de distribuerade systemens karaktär korsreferenser inte unika begränsningar eller referensintegritet mellan arbetsnoder i Azure Cosmos DB for PostgreSQL.

Om du vill konfigurera en sekundärnyckel mellan samallokerade distribuerade tabeller ska du alltid inkludera distributionskolumnen i nyckeln. Att inkludera distributionskolumnen kan innebära att göra nyckelföreningen.

Sekundärnycklar kan skapas i följande situationer:

  • mellan två lokala (icke-distribuerade) tabeller,
  • mellan två referenstabeller,
  • mellan två samallokerade distribuerade tabeller när nyckeln innehåller distributionskolumnen, eller
  • som en distribuerad tabell som refererar till en referenstabell

Sekundärnycklar från referenstabeller till distribuerade tabeller stöds inte.

Kommentar

Primära nycklar och unika begränsningar måste innehålla distributionskolumnen. Om du lägger till dem i en icke-distributionskolumn genereras ett fel

Det här exemplet visar hur du skapar primära och externa nycklar i distribuerade tabeller:

--
-- Adding a primary key
-- --------------------

-- We'll distribute these tables on the account_id. The ads and clicks
-- tables must use compound keys that include account_id.

ALTER TABLE accounts ADD PRIMARY KEY (id);
ALTER TABLE ads ADD PRIMARY KEY (account_id, id);
ALTER TABLE clicks ADD PRIMARY KEY (account_id, id);

-- Next distribute the tables

SELECT create_distributed_table('accounts', 'id');
SELECT create_distributed_table('ads',      'account_id');
SELECT create_distributed_table('clicks',   'account_id');

--
-- Adding foreign keys
-- -------------------

-- Note that this can happen before or after distribution, as long as
-- there exists a uniqueness constraint on the target column(s) which
-- can only be enforced before distribution.

ALTER TABLE ads ADD CONSTRAINT ads_account_fk
  FOREIGN KEY (account_id) REFERENCES accounts (id);
ALTER TABLE clicks ADD CONSTRAINT clicks_ad_fk
  FOREIGN KEY (account_id, ad_id) REFERENCES ads (account_id, id);

På samma sätt kan du inkludera distributionskolumnen i unika begränsningar:

-- Suppose we want every ad to use a unique image. Notice we can
-- enforce it only per account when we distribute by account id.

ALTER TABLE ads ADD CONSTRAINT ads_unique_image
  UNIQUE (account_id, image_url);

Begränsningar som inte är null kan tillämpas på valfri kolumn (distribution eller inte) eftersom de inte kräver några sökningar mellan arbetare.

ALTER TABLE ads ALTER COLUMN image_url SET NOT NULL;

Använda OGILTIGa begränsningar

I vissa situationer kan det vara användbart att framtvinga begränsningar för nya rader, samtidigt som befintliga rader som inte överensstämmer förblir oförändrade. Azure Cosmos DB for PostgreSQL stöder den här funktionen för CHECK-begränsningar och sekundärnycklar, med postgreSQL:s villkorsbeteckning "NOT VALID".

Tänk dig till exempel ett program som lagrar användarprofiler i en referenstabell.

-- we're using the "text" column type here, but a real application
-- might use "citext" which is available in a postgres contrib module

CREATE TABLE users ( email text PRIMARY KEY );
SELECT create_reference_table('users');

Tänk dig att några icke-adresser kommer in i tabellen.

INSERT INTO users VALUES
   ('foo@example.com'), ('hacker12@aol.com'), ('lol');

Vi vill verifiera adresserna, men PostgreSQL tillåter normalt inte att vi lägger till en CHECK-begränsning som misslyckas för befintliga rader. Men det tillåter en begränsning som är markerad som ogiltig:

ALTER TABLE users
ADD CONSTRAINT syntactic_email
CHECK (email ~
   '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
) NOT VALID;

Nya rader är nu skyddade.

INSERT INTO users VALUES ('fake');

/*
ERROR:  new row for relation "users_102010" violates
        check constraint "syntactic_email_102010"
DETAIL:  Failing row contains (fake).
*/

Senare, under tider med hög belastning, kan en databasadministratör försöka åtgärda de felaktiga raderna och återskapa villkoret.

-- later, attempt to validate all rows
ALTER TABLE users
VALIDATE CONSTRAINT syntactic_email;

PostgreSQL-dokumentationen innehåller mer information om INTE GILTIG och VALIDERA BEGRÄNSNING i avsnittet ALTER TABLE .

Lägga till/ta bort index

Azure Cosmos DB for PostgreSQL stöder tillägg och borttagning av index:

-- Adding an index

CREATE INDEX clicked_at_idx ON clicks USING BRIN (clicked_at);

-- Removing an index

DROP INDEX clicked_at_idx;

Att lägga till ett index tar ett skrivlås, vilket kan vara oönskat i en "system-of-record" för flera klientorganisationer. För att minimera programavbrott skapar du indexet samtidigt i stället. Den här metoden kräver mer totalt arbete än en standardindexversion och tar längre tid att slutföra. Men eftersom det gör att normala åtgärder kan fortsätta medan indexet skapas är den här metoden användbar för att lägga till nya index i en produktionsmiljö.

-- Adding an index without locking table writes

CREATE INDEX CONCURRENTLY clicked_at_idx ON clicks USING BRIN (clicked_at);

Typer och funktioner

Skapa anpassade SQL-typer och användardefinierade funktioner propogates till arbetsnoder. Att skapa sådana databasobjekt i en transaktion med distribuerade åtgärder innebär dock kompromisser.

Azure Cosmos DB for PostgreSQL parallelliserar åtgärder, till exempel create_distributed_table() mellan shards med flera anslutningar per arbetare. När du skapar ett databasobjekt sprider Azure Cosmos DB for PostgreSQL det till arbetsnoder med en enda anslutning per arbetare. Att kombinera de två åtgärderna i en enda transaktion kan orsaka problem, eftersom de parallella anslutningarna inte kommer att kunna se objektet som skapades via en enda anslutning men som ännu inte har checkats in.

Överväg ett transaktionsblock som skapar en typ, en tabell, läser in data och distribuerar tabellen:

BEGIN;

-- type creation over a single connection:
CREATE TYPE coordinates AS (x int, y int);
CREATE TABLE positions (object_id text primary key, position coordinates);

-- data loading thus goes over a single connection:
SELECT create_distributed_table(‘positions’, ‘object_id’);

SET client_encoding TO 'UTF8';
\COPY positions FROM ‘positions.csv’

COMMIT;

Innan Citus 11.0 skulle Citus skjuta upp skapandet av typen på arbetsnoderna och checka in den separat när du skapar den distribuerade tabellen. Detta gjorde det möjligt att kopiera create_distributed_table() in data parallellt. Men det innebar också att typen inte alltid fanns på Citus-arbetsnoderna – eller om transaktionen återställdes skulle typen finnas kvar på arbetsnoderna.

Med Citus 11.0 ändras standardbeteendet för att prioritera schemakonsekvens mellan koordinator- och arbetsnoder. Det nya beteendet har en nackdel: om objektspridning sker efter ett parallellt kommando i samma transaktion kan transaktionen inte längre slutföras, vilket markeras av FELET i kodblocket nedan:

BEGIN;
CREATE TABLE items (key text, value text);
-- parallel data loading:
SELECT create_distributed_table(‘items’, ‘key’);
SET client_encoding TO 'UTF8';
\COPY items FROM ‘items.csv’
CREATE TYPE coordinates AS (x int, y int);

ERROR:  cannot run type command because there was a parallel operation on a distributed table in the transaction

Om du stöter på det här problemet finns det två enkla lösningar:

  1. Använd inställd citus.create_object_propagation på för att automatic skjuta upp skapandet av typen i den här situationen, i vilket fall det kan finnas viss inkonsekvens mellan vilka databasobjekt som finns på olika noder.
  2. Använd inställd citus.multi_shard_modify_mode på för att sequential inaktivera parallellitet per nod. Datainläsningen i samma transaktion kan vara långsammare.

Nästa steg