Táblák terjesztése és módosítása az Azure Cosmos DB for PostgreSQL-ben

A KÖVETKEZŐKRE VONATKOZIK: Azure Cosmos DB for PostgreSQL (a Citus-adatbázis PostgreSQL-hez való kiterjesztése)

Táblák elosztása

Elosztott tábla létrehozásához először meg kell határoznia a táblasémát. Ehhez ugyanúgy definiálhat egy táblát a CREATE TABLE utasítással, mint egy normál PostgreSQL-táblával.

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

Ezután a create_distributed_table() függvénnyel megadhatja a táblaterjesztési oszlopot, és létrehozhatja a feldolgozó szegmenseket.

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

A függvényhívás tájékoztatja az Azure Cosmos DB for PostgreSQL-t, hogy a github_events táblát el kell osztani a repo_id oszlopban (az oszlopérték kivonatolásával).

Alapértelmezés szerint összesen 32 szegmenst hoz létre, ahol minden szegmens egy kivonatterület egy részét birtokolja, és az alapértelmezett citus.shard_replication_factor konfigurációs érték alapján replikálódik. A feldolgozón létrehozott szegmensreplikák ugyanazokkal a táblasémával, indexeléssel és kényszerdefiníciókkal rendelkeznek, mint a koordinátor táblája. A replikák létrehozása után a függvény az összes elosztott metaadatot menti a koordinátorba.

Minden létrehozott szegmenshez egyedi szegmensazonosító tartozik, és az összes replika azonos szegmensazonosítóval rendelkezik. A szegmensek a munkavégző csomóponton "tablename_shardid" nevű normál PostgreSQL-táblákként jelennek meg, ahol a táblanév az elosztott tábla neve, a szegmensazonosító pedig a hozzárendelt egyedi azonosító. A munkavégző postgres-példányokhoz kapcsolódva megtekintheti vagy futtathatja a parancsokat az egyes szegmenseken.

Most már készen áll arra, hogy adatokat szúrjon be az elosztott táblába, és lekérdezéseket futtasson rajta. Az ebben a szakaszban használt UDF-ről és a szegmensek DDL-referenciájáról is tájékozódhat.

Referenciatáblák

A fenti módszer több vízszintes szegmensbe osztja a táblákat. Egy másik lehetőség a táblák elosztása egyetlen szegmensbe, és a szegmens replikálása minden munkavégző csomópontra. Az így elosztott táblákat referenciatábláknak nevezzük. Ezek olyan adatok tárolására szolgálnak, amelyeket gyakran kell elérni egy fürt több csomópontja számára.

A referenciatáblák gyakori jelöltjei a következők:

  • Kisebb táblák, amelyeknek nagyobb elosztott táblákkal kell csatlakozniuk.
  • Több-bérlős alkalmazások olyan táblái, amelyek nem tartalmaznak bérlőazonosító oszlopot, vagy amelyek nincsenek bérlőhöz társítva. (Vagy a migrálás során, még a bérlőhöz társított táblák esetében is.)
  • Azok a táblák, amelyek több oszlopra kiterjedő egyedi korlátozásokat igényelnek, és elég kicsik.

Tegyük fel például, hogy egy több-bérlős e-kereskedelmi webhelynek ki kell számítania az összes üzletében végrehajtott tranzakciók forgalmi adóját. Az adóinformációk nem egy bérlőre vonatkoznak. Érdemes egy megosztott táblába helyezni. Az USA-központú referenciatáblák a következőképpen néznek ki:

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

Az olyan lekérdezések, mint egy bevásárlókocsi adójának kiszámítása, hálózati terhelés nélkül csatlakozhatnak a states táblához, és hozzáadhatnak egy idegen kulcsot az állapotkódhoz a jobb ellenőrzés érdekében.

Amellett, hogy egyetlen replikált szegmensként terjeszt egy táblát, az create_reference_table UDF referenciatáblaként jelöli meg az Azure Cosmos DB for PostgreSQL metaadattábláiban. Az Azure Cosmos DB for PostgreSQL automatikusan kétfázisú véglegesítéseket (2PC) hajt végre az ilyen módon megjelölt táblák módosításához, ami erős konzisztenciagaranciát biztosít.

Egy másik példa a referenciatáblák használatára: a több-bérlős adatbázis oktatóanyaga.

Koordinátor adatainak terjesztése

Ha egy meglévő PostgreSQL-adatbázist átalakítanak egy fürt koordinátorcsomópontjába, a táblákban lévő adatok hatékonyan és minimális megszakítással terjeszthetők egy alkalmazás számára.

A create_distributed_table korábban ismertetett függvény üres és nem üres táblákon is működik, az utóbbiak esetében pedig automatikusan elosztja a tábla sorait a fürtben. Tudni fogja, hogy az adatokat a "FIGYELEM: Adatok másolása a helyi táblából..." üzenet jelenlétével másolja-e. Például:

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)

A tábla írásai blokkolva lesznek az adatok migrálása közben, a függőben lévő írások pedig elosztott lekérdezésekként lesznek kezelve a függvény véglegesítése után. (Ha a függvény meghibásodik, a lekérdezések ismét helyiek lesznek.) Az olvasások a szokásos módon folytatódhatnak, és elosztott lekérdezésekké válnak a függvény véglegesítése után.

Az A és a B táblák elosztásakor, ahol az A idegen kulccsal rendelkezik A-nak, először ossza el a B kulcs céltáblát. Ha nem megfelelő sorrendben végzi el, az hibát fog okozni:

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

Ha nem lehet a megfelelő sorrendben terjeszteni, akkor dobja el az idegen kulcsokat, ossza el a táblákat, és hozza létre újra az idegen kulcsokat.

Amikor adatokat migrál egy külső adatbázisból, például az Amazon RDS-ből az Azure Cosmos DB for PostgreSQL-be, először hozza létre az Elosztott Azure Cosmos DB for PostgreSQL-táblákat a segítségével create_distributed_table, majd másolja az adatokat a táblába. Az elosztott táblákba való másolással elkerülhető, hogy elfogyjon a szabad terület a koordinátor csomópontján.

Táblák áthelyezése

A közös elhelyezés azt jelenti, hogy a kapcsolódó információk ugyanazon gépeken vannak tárolva. Hatékony lekérdezéseket tesz lehetővé, miközben kihasználja a teljes adatkészlet horizontális méretezhetőségét. További információt a közös elhelyezés című témakörben talál.

A táblák csoportokba vannak helyezve. A tábla társhelycsoport-hozzárendelésének manuális vezérléséhez használja a nem kötelező colocate_with paramétert create_distributed_table. Ha nem érdekli egy tábla kolocációja, akkor kihagyja ezt a paramétert. Alapértelmezés szerint az értékre 'default'van kapcsolva, amely a táblát bármely más, azonos terjesztési oszloptípussal, szegmensszámmal és replikációs tényezővel rendelkező alapértelmezett colocation táblával csoportosítja. Ha meg szeretné szakítani vagy frissíteni szeretné ezt az implicit társlokációt, használhatja a következőt 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');

Ha egy új tábla nem kapcsolódik a leendő implicit társlokációs csoportban lévő többi táblához, adja meg a következőt colocated_with => 'none': .

-- not co-located with other tables

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

A nem kapcsolódó tábláknak a saját társhelycsoportjukra való felosztása javítja a szegmensek újraegyensúlyozási teljesítményét, mivel az ugyanabban a csoportban lévő szegmenseket együtt kell áthelyezni.

Ha a táblák valóban kapcsolódnak egymáshoz (például amikor csatlakoznak hozzájuk), érdemes lehet explicit módon áthelyezni őket. A megfelelő kolocáció nyeresége fontosabb, mint a terheléselosztás.

Ha több táblát szeretne explicit módon elhelyezni, ossza el az egyiket, majd helyezze a többit a társhelycsoportba. Például:

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

A közös elhelyezési csoportokkal kapcsolatos információk a pg_dist_colocation táblában vannak tárolva, a pg_dist_partition pedig azt, hogy mely táblák vannak hozzárendelve a csoportokhoz.

Táblák eltávolítása

Az elosztott táblák eltávolításához használhatja a standard PostgreSQL DROP TABLE parancsot. A hagyományos táblákhoz hasonlóan a DROP TABLE is eltávolítja a céltábla indexeit, szabályait, eseményindítóit és kényszereit. Emellett a munkavégző csomópontokon lévő szegmenseket is elveti, és törli a metaadataikat.

DROP TABLE github_events;

Táblák módosítása

Az Azure Cosmos DB for PostgreSQL automatikusan propagálja a DDL-utasítások számos típusát. Ha módosít egy elosztott táblát a koordinátorcsomóponton, az a feldolgozók szegmenseit is frissíti. Más DDL-utasítások manuális propagálást igényelnek, és bizonyos egyéb utasítások nem engedélyezettek, például amelyek módosítanák a terjesztési oszlopokat. Ha olyan DDL-t próbál futtatni, amely nem jogosult az automatikus propagálásra, hibát jelez, és a koordinátorcsomóponton változatlanul hagyja a táblákat.

Íme egy hivatkozás a propagált DDL-utasítások kategóriáira.

Oszlopok hozzáadása/módosítása

Az Azure Cosmos DB for PostgreSQL automatikusan propagálja a legtöbb ALTER TABLE-parancsot . Az oszlopok hozzáadása vagy az alapértelmezett értékek módosítása ugyanúgy működik, mint egy egygépes PostgreSQL-adatbázisban:

-- Adding a column

ALTER TABLE products ADD COLUMN description text;

-- Changing default value

ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;

A meglévő oszlopok jelentős módosítása, például átnevezése vagy adattípusának módosítása is rendben van. A terjesztési oszlop adattípusa azonban nem módosítható. Ez az oszlop határozza meg, hogyan oszlanak el a táblaadatok a fürtön keresztül, és az adattípus módosításához át kell helyezned az adatokat.

Ennek megkísérlése hibát okoz:

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

Korlátozások hozzáadása/eltávolítása

Az Azure Cosmos DB for PostgreSQL használatával továbbra is élvezheti a relációs adatbázisok biztonságát, beleértve az adatbázis-korlátozásokat is (lásd a PostgreSQL dokumentációját). Az elosztott rendszerek természetéből adódóan az Azure Cosmos DB for PostgreSQL nem hivatkozik kereszthivatkozásokra a munkavégző csomópontok egyediségére vagy hivatkozási integritására.

Ha egy idegen kulcsot szeretne beállítani a megosztott elosztott táblák között, mindig foglalja bele a terjesztési oszlopot a kulcsba. A disztribúciós oszlop belefoglyulása magában foglalhatja a kulcsvegyület elkészítését is.

Ilyen esetekben idegen kulcsok hozhatók létre:

  • két helyi (nem elosztott) tábla között,
  • két referenciatábla között,
  • két megosztott elosztott tábla között, ha a kulcs tartalmazza a terjesztési oszlopot, vagy
  • hivatkozási táblára hivatkozó elosztott táblaként

A referenciatábláktól az elosztott táblákig nem támogatottak az idegen kulcsok.

Megjegyzés

Az elsődleges kulcsoknak és az egyediségi korlátozásoknak tartalmazniuk kell a terjesztési oszlopot. Ha nem terjesztési oszlopba adja őket, hibaüzenet jelenik meg

Ez a példa bemutatja, hogyan hozhat létre elsődleges és idegen kulcsokat elosztott táblákon:

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

Hasonlóképpen, foglalja bele a terjesztési oszlopot az egyediségi korlátozásokba:

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

A nem null értékű kényszerek bármely oszlopra (eloszlásra vagy sem) alkalmazhatók, mert nem igényelnek kereséseket a feldolgozók között.

ALTER TABLE ads ALTER COLUMN image_url SET NOT NULL;

ÉRVÉNYTELEN kényszerek használata

Bizonyos esetekben hasznos lehet kényszereket kényszeríteni az új sorokra, miközben a meglévő, nem megfelelő sorok változatlanok maradnak. Az Azure Cosmos DB for PostgreSQL támogatja ezt a funkciót a CHECK korlátozások és idegen kulcsok esetében a PostgreSQL "NEM ÉRVÉNYES" kényszermegjelölésével.

Vegyük például egy olyan alkalmazást, amely egy referenciatáblában tárolja a felhasználói profilokat.

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

Az idő során képzelje el, hogy néhány nem cím bekerül a táblába.

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

Szeretnénk ellenőrizni a címeket, de a PostgreSQL általában nem teszi lehetővé, hogy olyan CHECK kényszert adjunk hozzá, amely nem működik a meglévő sorok esetében. A korlátozás azonban nem érvényesként van megjelölve:

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;

Az új sorok mostantól védettek.

INSERT INTO users VALUES ('fake');

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

Később, csúcsidőn kívüli időszakokban az adatbázis-rendszergazda megpróbálhatja kijavítani a hibás sorokat, és újraértékelni a kényszert.

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

A PostgreSQL dokumentációja az ALTER TABLE szakaszban további információt tartalmaz a NEM ÉRVÉNYES és a VALIDATE CONSTRAINT kifejezésről.

Indexek hozzáadása/eltávolítása

Az Azure Cosmos DB for PostgreSQL támogatja az indexek hozzáadását és eltávolítását:

-- Adding an index

CREATE INDEX clicked_at_idx ON clicks USING BRIN (clicked_at);

-- Removing an index

DROP INDEX clicked_at_idx;

Az index hozzáadása írási zárolást igényel, ami nem kívánatos a több-bérlős "rekordrendszer" esetében. Az alkalmazás állásidejének minimalizálása érdekében hozza létre az indexet egyidejűleg . Ez a módszer több teljes munkát igényel, mint egy szabványos index build, és több időt vesz igénybe. Mivel azonban lehetővé teszi a normál műveletek folytatását az index létrehozása közben, ez a módszer hasznos új indexek éles környezetben való hozzáadásához.

-- Adding an index without locking table writes

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

Típusok és függvények

Az egyéni SQL-típusok és a felhasználó által definiált függvények létrehozása a munkavégző csomópontokra is kihat. Az ilyen adatbázis-objektumok elosztott műveletekkel végzett tranzakcióban való létrehozása azonban kompromisszumokkal jár.

Az Azure Cosmos DB for PostgreSQL párhuzamosítja az olyan műveleteket, mint például create_distributed_table() a szegmensek között, feldolgozónként több kapcsolat használatával. Míg egy adatbázis-objektum létrehozásakor az Azure Cosmos DB for PostgreSQL egy feldolgozói kapcsolat használatával propagálja azt a munkavégző csomópontokra. A két művelet egyetlen tranzakcióban való kombinálása problémákat okozhat, mivel a párhuzamos kapcsolatok nem fogják látni az egyetlen kapcsolaton keresztül létrehozott, de még nem véglegesített objektumot.

Vegyünk egy tranzakcióblokkot, amely létrehoz egy típust, egy táblát, betölti az adatokat, és elosztja a táblát:

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;

A Citus 11.0-s verzióját megelőzően a Citus elhalasztotta a típus létrehozását a munkavégző csomópontokon, és külön véglegesíti azt az elosztott tábla létrehozásakor. Ez lehetővé tette az adatok párhuzamos másolását create_distributed_table() . Azt is jelentette azonban, hogy a típus nem volt mindig jelen a Citus-munkavégző csomópontokon – vagy ha a tranzakció vissza lett állítva, a típus a munkavégző csomópontokon maradna.

A Citus 11.0-val az alapértelmezett viselkedés megváltozik a sémakonzisztenciának a koordinátor és a munkavégző csomópontok közötti rangsorolása érdekében. Az új viselkedésnek van egy hátránya: ha az objektumpropagálás egy párhuzamos parancs után történik ugyanabban a tranzakcióban, akkor a tranzakció már nem hajtható végre, ahogy azt az alábbi kódblokk hibakódja is kiemeli:

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

Ha ezt a problémát tapasztalja, két egyszerű megkerülő megoldás létezik:

  1. A halmaz citus.create_object_propagationautomatic használatával késleltetheti a típus létrehozását ebben az esetben, amely esetben inkonzisztenciát okozhat, hogy mely adatbázis-objektumok léteznek a különböző csomópontokon.
  2. A halmaz citus.multi_shard_modify_mode használatával sequential letilthatja a csomópontonkénti párhuzamosságot. Előfordulhat, hogy ugyanabban a tranzakcióban lassabb az adatbetöltés.

Következő lépések