Tabellen distribueren en wijzigen in Azure Cosmos DB for PostgreSQL

VAN TOEPASSING OP: Azure Cosmos DB for PostgreSQL (mogelijk gemaakt door de Citus-databaseextensie voor PostgreSQL)

Tabellen distribueren

Als u een gedistribueerde tabel wilt maken, moet u eerst het tabelschema definiëren. Hiervoor kunt u een tabel definiëren met behulp van de instructie CREATE TABLE op dezelfde manier als bij een gewone PostgreSQL-tabel.

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

Vervolgens kunt u de functie create_distributed_table() gebruiken om de tabeldistributiekolom op te geven en de werkrolshards te maken.

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

De functieaanroep informeert Azure Cosmos DB for PostgreSQL dat de github_events tabel moet worden gedistribueerd op de repo_id kolom (door de kolomwaarde te hashen).

Er worden standaard in totaal 32 shards gemaakt, waarbij elke shard eigenaar is van een gedeelte van een hash-ruimte en wordt gerepliceerd op basis van de standaardconfiguratiewaarde citus.shard_replication_factor. De shard-replica's die op de werkrol zijn gemaakt, hebben dezelfde tabelschema-, index- en beperkingsdefinities als de tabel op de coördinator. Zodra de replica's zijn gemaakt, slaat de functie alle gedistribueerde metagegevens op de coördinator op.

Aan elke gemaakte shard wordt een unieke shard-id toegewezen en alle replica's hebben dezelfde shard-id. Shards worden op het werkknooppunt weergegeven als gewone PostgreSQL-tabellen met de naam 'tablename_shardid', waarbij tablename de naam is van de gedistribueerde tabel en shard-id de unieke toegewezen id is. U kunt verbinding maken met de worker postgres-exemplaren om opdrachten op afzonderlijke shards weer te geven of uit te voeren.

U bent nu klaar om gegevens in te voegen in de gedistribueerde tabel en er query's op uit te voeren. In deze sectie vindt u ook meer informatie over de UDF die wordt gebruikt in de tabel- en shard-DDL-verwijzing .

Referentietabellen

Met de bovenstaande methode worden tabellen verdeeld over meerdere horizontale shards. Een andere mogelijkheid is het distribueren van tabellen in één shard en het repliceren van de shard naar elk werkknooppunt. Tabellen die op deze manier worden gedistribueerd, worden referentietabellen genoemd. Ze worden gebruikt voor het opslaan van gegevens die regelmatig moeten worden geopend door meerdere knooppunten in een cluster.

Veelvoorkomende kandidaten voor referentietabellen zijn:

  • Kleinere tabellen die moeten worden samengevoegd met grotere gedistribueerde tabellen.
  • Tabellen in apps met meerdere tenants die geen tenant-id-kolom hebben of die niet zijn gekoppeld aan een tenant. (Of, tijdens de migratie, zelfs voor sommige tabellen die zijn gekoppeld aan een tenant.)
  • Tabellen waarvoor unieke beperkingen in meerdere kolommen nodig zijn en die klein genoeg zijn.

Stel dat een eCommerce-site met meerdere tenants btw moet berekenen voor transacties in een van de winkels. Belastinggegevens zijn niet specifiek voor een tenant. Het is zinvol om deze in een gedeelde tabel te plaatsen. Een op de VS gerichte referentietabel kan er als volgt uitzien:

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

Query's zoals een berekening van de belasting voor een winkelwagen kunnen nu zonder netwerkoverhead aan de states tabel worden toegevoegd en kunnen een refererende sleutel toevoegen aan de staatscode voor een betere validatie.

Naast het distribueren van een tabel als één gerepliceerde shard, markeert de UDF deze create_reference_table als een referentietabel in de Azure Cosmos DB for PostgreSQL-metagegevenstabellen. Azure Cosmos DB for PostgreSQL voert automatisch tweefasen doorvoeringen (2PC) uit voor wijzigingen in tabellen die op deze manier zijn gemarkeerd, wat sterke consistentiegaranties biedt.

Zie de zelfstudie database met meerdere tenants voor een ander voorbeeld van het gebruik van referentietabellen.

Coördinatorgegevens distribueren

Als een bestaande PostgreSQL-database wordt geconverteerd naar het coördinatorknooppunt voor een cluster, kunnen de gegevens in de tabellen efficiënt en met minimale onderbreking naar een toepassing worden gedistribueerd.

De create_distributed_table eerder beschreven functie werkt voor zowel lege als niet-lege tabellen, en voor de laatste functie worden tabelrijen automatisch verdeeld over het cluster. U weet of er gegevens worden gekopieerd door de aanwezigheid van het bericht 'KENNISGEVING: gegevens kopiëren uit lokale tabel...' Bijvoorbeeld:

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)

Schrijfbewerkingen in de tabel worden geblokkeerd terwijl de gegevens worden gemigreerd en in behandeling zijnde schrijfbewerkingen worden verwerkt als gedistribueerde query's zodra de functie is doorgevoerd. (Als de functie mislukt, worden de query's weer lokaal.) Leesbewerkingen kunnen gewoon doorgaan en worden gedistribueerde query's zodra de functie is doorgevoerd.

Wanneer u de tabellen A en B distribueert, waarbij A een refererende sleutel voor B heeft, distribueert u eerst de sleuteldoeltabel B. Als u dit in de verkeerde volgorde doet, treedt er een fout op:

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

Als het niet mogelijk is om in de juiste volgorde te distribueren, verwijdert u de refererende sleutels, distribueert u de tabellen en maakt u de refererende sleutels opnieuw.

Wanneer u gegevens migreert van een externe database, zoals van Amazon RDS naar Azure Cosmos DB for PostgreSQL, maakt u eerst de gedistribueerde Azure Cosmos DB for PostgreSQL-tabellen via create_distributed_tableen kopieert u de gegevens vervolgens naar de tabel. Als u naar gedistribueerde tabellen kopieert, voorkomt u dat er onvoldoende ruimte is op het coördinatorknooppunt.

Tabellen coloceren

Colocatie betekent het bewaren van gerelateerde informatie op dezelfde machines. Het maakt efficiënte query's mogelijk en profiteert van de horizontale schaalbaarheid voor de hele gegevensset. Zie colocatie voor meer informatie.

Tabellen worden gegroepeerd in groepen. Als u de groepstoewijzing voor co-locatie van een tabel handmatig wilt beheren, gebruikt u de optionele colocate_with parameter van create_distributed_table. Als u de colocatie van een tabel niet belangrijk vindt, laat u deze parameter weg. Standaard wordt de waarde 'default'gebruikt, waarmee de tabel wordt gegroepeerd met een andere standaard colocatietabel met hetzelfde type distributiekolom, shardaantal en replicatiefactor. Als u deze impliciete colocatie wilt onderbreken of bijwerken, kunt u gebruiken 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');

Wanneer een nieuwe tabel niet is gerelateerd aan anderen in de impliciete colocatiegroep die zou worden, geeft u colocated_with => 'none'op.

-- not co-located with other tables

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

Als u niet-gerelateerde tabellen splitst in hun eigen colocatiegroepen, worden de shard-herverdelingsprestaties verbeterd, omdat shards in dezelfde groep samen moeten worden verplaatst.

Wanneer tabellen inderdaad gerelateerd zijn (bijvoorbeeld wanneer ze worden samengevoegd), kan het zinvol zijn om ze expliciet te colocatie. De voordelen van de juiste colocatie zijn belangrijker dan eventuele herverdelingsoverhead.

Als u expliciet meerdere tabellen wilt plaatsen, distribueert u een tabel en plaatst u de andere tabellen in de colocatiegroep. Bijvoorbeeld:

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

Informatie over colocatiegroepen wordt opgeslagen in de pg_dist_colocation tabel, terwijl pg_dist_partition laat zien welke tabellen aan welke groepen zijn toegewezen.

Tabellen neerzetten

U kunt de standaardopdracht PostgreSQL DROP TABLE gebruiken om uw gedistribueerde tabellen te verwijderen. Net als bij gewone tabellen verwijdert DROP TABLE alle indexen, regels, triggers en beperkingen voor de doeltabel. Daarnaast worden ook de shards op de werkknooppunten weggeslagen en worden hun metagegevens opgeschoond.

DROP TABLE github_events;

Tabellen wijzigen

In Azure Cosmos DB for PostgreSQL worden automatisch veel soorten DDL-instructies doorgegeven. Als u een gedistribueerde tabel wijzigt op het coördinatorknooppunt, worden ook shards op de werkrollen bijgewerkt. Voor andere DDL-instructies is handmatige doorgifte vereist en sommige andere zijn verboden, zoals elke die een distributiekolom zou wijzigen. Als u probeert DDL uit te voeren die niet in aanmerking komt voor automatische doorgifte, treedt er een fout op en blijven tabellen op het coördinatorknooppunt ongewijzigd.

Hier volgt een verwijzing naar de categorieën DDL-instructies die worden doorgegeven.

Kolommen toevoegen/wijzigen

Azure Cosmos DB for PostgreSQL geeft de meeste ALTER TABLE-opdrachten automatisch door. Het toevoegen van kolommen of het wijzigen van de standaardwaarden werkt zoals in een PostgreSQL-database met één machine:

-- Adding a column

ALTER TABLE products ADD COLUMN description text;

-- Changing default value

ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;

Belangrijke wijzigingen in een bestaande kolom, zoals het wijzigen van de naam of het wijzigen van het gegevenstype, zijn ook prima. Het gegevenstype van de distributiekolom kan echter niet worden gewijzigd. Deze kolom bepaalt hoe tabelgegevens worden gedistribueerd via het cluster. Als u het gegevenstype wilt wijzigen, moeten de gegevens worden verplaatst.

Als u dit probeert, wordt er een fout veroorzaakt:

-- 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
*/

Beperkingen toevoegen/verwijderen

Als u Azure Cosmos DB for PostgreSQL gebruikt, kunt u blijven profiteren van de veiligheid van een relationele database, inclusief databasebeperkingen (zie de PostgreSQL-documenten). Vanwege de aard van gedistribueerde systemen verwijst Azure Cosmos DB for PostgreSQL niet naar beperkingen van uniekheid of referentiële integriteit tussen werkknooppunten.

Als u een refererende sleutel tussen gedistribueerde tabellen met een locatie wilt instellen, moet u altijd de distributiekolom in de sleutel opnemen. Het opnemen van de distributiekolom kan betekenen dat de sleutelverbinding wordt gemaakt.

In deze situaties kunnen refererende sleutels worden gemaakt:

Refererende sleutels van referentietabellen naar gedistribueerde tabellen worden niet ondersteund.

Notitie

Primaire sleutels en uniciteitsbeperkingen moeten de distributiekolom omvatten. Als u ze toevoegt aan een niet-distributiekolom, wordt er een fout gegenereerd

In dit voorbeeld ziet u hoe u primaire en refererende sleutels maakt voor gedistribueerde tabellen:

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

Neem op dezelfde manier de distributiekolom op in beperkingen voor uniekheid:

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

Niet-null-beperkingen kunnen worden toegepast op elke kolom (distributie of niet) omdat hiervoor geen zoekacties tussen werkrollen zijn vereist.

ALTER TABLE ads ALTER COLUMN image_url SET NOT NULL;

Niet geldige beperkingen gebruiken

In sommige situaties kan het handig zijn om beperkingen af te dwingen voor nieuwe rijen, terwijl bestaande niet-conforme rijen ongewijzigd blijven. Azure Cosmos DB for PostgreSQL ondersteunt deze functie voor CHECK-beperkingen en refererende sleutels, met behulp van de beperkingsaanduiding 'NIET GELDIG' van PostgreSQL.

Denk bijvoorbeeld aan een toepassing die gebruikersprofielen opslaat in een referentietabel.

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

Stel dat in de loop van de tijd enkele niet-adressen in de tabel komen.

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

We willen de adressen valideren, maar PostgreSQL staat ons doorgaans niet toe om een CHECK-beperking toe te voegen die mislukt voor bestaande rijen. Er is echter wel een beperking toegestaan die is gemarkeerd als ongeldig:

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;

Nieuwe rijen zijn nu beveiligd.

INSERT INTO users VALUES ('fake');

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

Later, tijdens niet-piekuren, kan een databasebeheerder proberen de beschadigde rijen op te lossen en de beperking opnieuw tevalideren.

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

De PostgreSQL-documentatie bevat meer informatie over NOT VALID en VALIDATE CONSTRAINT in de sectie ALTER TABLE .

Indexen toevoegen/verwijderen

Azure Cosmos DB for PostgreSQL biedt ondersteuning voor het toevoegen en verwijderen van indexen:

-- Adding an index

CREATE INDEX clicked_at_idx ON clicks USING BRIN (clicked_at);

-- Removing an index

DROP INDEX clicked_at_idx;

Voor het toevoegen van een index is een schrijfvergrendeling nodig, wat ongewenst kan zijn in een 'systeem-van-record' met meerdere tenants. Als u downtime van toepassingen wilt minimaliseren, maakt u de index gelijktijdig . Deze methode vereist meer totale werk dan een standaardindexbuild en duurt langer om te voltooien. Omdat normale bewerkingen echter kunnen worden voortgezet terwijl de index wordt gebouwd, is deze methode handig voor het toevoegen van nieuwe indexen in een productieomgeving.

-- Adding an index without locking table writes

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

Typen en functies

Het maken van aangepaste SQL-typen en door de gebruiker gedefinieerde functies propogaats naar werkknooppunten. Het maken van dergelijke databaseobjecten in een transactie met gedistribueerde bewerkingen omvat echter compromissen.

Azure Cosmos DB for PostgreSQL parallelliseert bewerkingen zoals create_distributed_table() tussen shards met behulp van meerdere verbindingen per werkrol. Bij het maken van een databaseobject wordt dit door Azure Cosmos DB for PostgreSQL doorgegeven aan werkknooppunten met behulp van één verbinding per werkrol. Het combineren van de twee bewerkingen in één transactie kan problemen veroorzaken, omdat de parallelle verbindingen het object niet kunnen zien dat via één verbinding is gemaakt, maar nog niet is doorgevoerd.

Denk aan een transactieblok dat een type, een tabel maakt, gegevens laadt en de tabel distribueert:

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;

Vóór Citus 11.0 heeft Citus het maken van het type op de werkknooppunten uitstellen en dit afzonderlijk doorgevoerd bij het maken van de gedistribueerde tabel. Hierdoor kon het kopiëren van create_distributed_table() gegevens parallel plaatsvinden. Dit betekende echter ook dat het type niet altijd aanwezig was op de Citus-werkknooppunten. Als de transactie werd teruggedraaid, bleef het type op de werkknooppunten staan.

Met Citus 11.0 verandert het standaardgedrag om prioriteit te geven aan schemaconsistentie tussen coördinator- en werkknooppunten. Het nieuwe gedrag heeft een nadeel: als objectdoorgifte plaatsvindt na een parallelle opdracht in dezelfde transactie, kan de transactie niet meer worden voltooid, zoals wordt aangegeven door de FOUT in het onderstaande codeblok:

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

Als u dit probleem ondervindt, zijn er twee eenvoudige tijdelijke oplossingen:

  1. Gebruik ingesteld citus.create_object_propagation op automatic om het maken van het type in deze situatie uit te stellen. In dat geval kan er een inconsistentie zijn tussen de databaseobjecten op verschillende knooppunten.
  2. Gebruik ingesteld citus.multi_shard_modify_mode op sequential om parallellisme per knooppunt uit te schakelen. Het laden van gegevens in dezelfde transactie kan langzamer zijn.

Volgende stappen