Distribuce a úprava tabulek ve službě Azure Cosmos DB for PostgreSQL
PLATÍ PRO: Azure Cosmos DB for PostgreSQL (využívající rozšíření databáze Citus do PostgreSQL)
Distribuce tabulek
Pokud chcete vytvořit distribuovanou tabulku, musíte nejprve definovat schéma tabulky. K tomu můžete definovat tabulku pomocí příkazu CREATE TABLE stejným způsobem jako u běžné tabulky PostgreSQL.
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
);
Dále můžete pomocí funkce create_distributed_table() určit distribuční sloupec tabulky a vytvořit horizontální oddíly pracovního procesu.
SELECT create_distributed_table('github_events', 'repo_id');
Volání funkce informuje službu Azure Cosmos DB for PostgreSQL, že by se tabulka github_events měla distribuovat do sloupce repo_id (zatřiďováním hodnoty sloupce).
Ve výchozím nastavení vytvoří celkem 32 horizontálních oddílů, kde každý horizontální oddíl vlastní část prostoru hash a replikuje se na základě výchozí hodnoty konfigurace citus.shard_replication_factor. Repliky horizontálních oddílů vytvořené v pracovním procesu mají stejné definice schématu tabulky, indexu a omezení jako definice tabulky v koordinátoru. Po vytvoření replik uloží funkce všechna distribuovaná metadata na koordinátora.
Každému vytvořenému horizontálnímu oddílu se přiřadí jedinečné ID horizontálního oddílu a všechny jeho repliky mají stejné ID horizontálního oddílu. Horizontální oddíly jsou na pracovním uzlu reprezentovány jako běžné tabulky PostgreSQL s názvem "tablename_shardid", kde název tabulky je název distribuované tabulky, a ID horizontálního oddílu je jedinečné přiřazené ID. Můžete se připojit k instancím postgres pracovního procesu a zobrazit nebo spustit příkazy v jednotlivých horizontálních oddílech.
Teď jste připraveni vložit data do distribuované tabulky a spouštět na ní dotazy. Další informace o UDF použitém v této části najdete v referenčních informacích k tabulce a horizontálnímu oddílu DDL .
Referenční tabulky
Výše uvedená metoda distribuuje tabulky do několika horizontálních horizontálních horizontálních oddílů. Další možností je distribuce tabulek do jednoho horizontálního oddílu a replikace horizontálního oddílu do každého pracovního uzlu. Tabulky distribuované tímto způsobem se nazývají referenční tabulky. Používají se k ukládání dat, ke kterým je potřeba často přistupovat více uzlů v clusteru.
Mezi běžné kandidáty pro referenční tabulky patří:
- Menší tabulky, které je potřeba spojit s většími distribuovanými tabulkami.
- Tabulky v aplikacích s více tenanty, které nemají sloupec ID tenanta nebo které nejsou přidružené k tenantovi. (Nebo během migrace, i u některých tabulek přidružených k tenantovi.)
- Tabulky, které potřebují jedinečná omezení ve více sloupcích a jsou dostatečně malé.
Předpokládejme například, že web elektronického obchodování s více tenanty musí vypočítat daň z prodeje pro transakce v libovolném úložišti. Daňové údaje nejsou specifické pro žádného tenanta. Dává smysl ji umístit do sdílené tabulky. Referenční tabulka zaměřená na USA může vypadat takto:
-- 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');
Teď se dotazy, jako je například jeden výpočet daně z nákupního košíku, mohou připojit k states
tabulce bez síťové režie a přidat cizí klíč do kódu státu pro lepší ověření.
Kromě distribuce tabulky jako jediného replikovaného horizontálního oddílu create_reference_table
ji funkce definovaná uživatelem označí jako referenční tabulku v tabulkách metadat Azure Cosmos DB for PostgreSQL. Azure Cosmos DB for PostgreSQL automaticky provádí dvoufázová potvrzení (2PC) pro úpravy tabulek označených tímto způsobem, což poskytuje záruky silné konzistence.
Další příklad použití referenčních tabulek najdete v kurzu databáze s více tenanty.
Distribuce dat koordinátora
Pokud je existující databáze PostgreSQL převedena na koordinační uzel clusteru, data v jejích tabulkách se dají efektivně distribuovat a s minimálním přerušením aplikace.
Funkce create_distributed_table
popsaná dříve funguje na prázdných i neprázdných tabulkách a u druhé tabulky automaticky distribuuje řádky tabulky v celém clusteru. Budete vědět, jestli kopíruje data podle přítomnosti zprávy, "NOTICE: Copying data from local table..." (OZNÁMENÍ: Kopírování dat z místní tabulky... Například:
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)
Zápisy v tabulce se během migrace dat zablokují a čekající zápisy se zpracovávají jako distribuované dotazy po potvrzení funkce. (Pokud funkce selže, dotazy se znovu stanou místním.) Čtení může pokračovat v normálním stavu a po potvrzení funkce se stanou distribuovanými dotazy.
Při distribuci tabulek A a B, kde A má cizí klíč do B, nejprve distribuujte cílovou tabulku klíče B. Když to uděláte v nesprávném pořadí, dojde k chybě:
ERROR: cannot create foreign key constraint
DETAIL: Referenced table must be a distributed table or a reference table.
Pokud není možné distribuovat ve správném pořadí, zahoďte cizí klíče, distribuujte tabulky a vytvořte cizí klíče znovu.
Při migraci dat z externí databáze, například z Amazon RDS do Azure Cosmos DB for PostgreSQL, nejprve vytvořte distribuované tabulky Azure Cosmos DB for PostgreSQL prostřednictvím create_distributed_table
a zkopírujte data do tabulky.
Kopírování do distribuovaných tabulek zabraňuje výpadku místa na koordinačním uzlu.
Společné přidělení tabulek
Kolokace znamená umístění souvisejících informací na stejných počítačích. Umožňuje efektivní dotazy a současně využívá horizontální škálovatelnost celé datové sady. Další informace najdete v tématu kolokace.
Tabulky se společně přidělují ve skupinách. Chcete-li ručně řídit přiřazení skupiny umístění tabulky, použijte volitelný colocate_with
parametr create_distributed_table
. Pokud vás nezajímá kolokace tabulky, vyloučíte tento parametr. Výchozí hodnota je hodnota 'default'
, která seskupí tabulku s jakoukoli jinou výchozí kolokací tabulkou se stejným typem distribučního sloupce, počtem horizontálních oddílů a faktorem replikace. Pokud chcete přerušit nebo aktualizovat tuto implicitní kolokaci, můžete použí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');
Pokud nová tabulka nesouvisí s ostatními ve své implicitní kolokační skupině, zadejte colocated_with => 'none'
.
-- not co-located with other tables
SELECT create_distributed_table('A', 'foo', colocate_with => 'none');
Rozdělení nesouvisejících tabulek do vlastních skupin kolokace zlepší výkon vyrovnávání horizontálních oddílů, protože horizontální oddíly ve stejné skupině se musí přesunout společně.
Pokud jsou tabulky skutečně související (například když budou spojeny), může mít smysl je explicitně umístit. Zisky odpovídající kolokace jsou důležitější než jakákoli rebalancující režie.
Pokud chcete explicitně umístit více tabulek, rozmístit jednu a potom ostatní umístit do své skupiny kolokace. Příklad:
-- 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');
Informace o skupinách kolokace jsou uloženy v pg_dist_colocation tabulce, zatímco pg_dist_partition odhalí, které tabulky jsou přiřazeny ke skupinám.
Vyřazení tabulek
K odebrání distribuovaných tabulek můžete použít standardní příkaz PostgreSQL DROP TABLE. Stejně jako u běžných tabulek funkce DROP TABLE odebere všechny indexy, pravidla, triggery a omezení, které existují pro cílovou tabulku. Kromě toho také zahodí horizontální oddíly na pracovních uzlech a vyčistí jejich metadata.
DROP TABLE github_events;
Úprava tabulek
Azure Cosmos DB for PostgreSQL automaticky šíří mnoho druhů příkazů DDL. Úpravou distribuované tabulky v koordinačním uzlu se také aktualizují horizontální oddíly pracovních procesů. Jiné příkazy DDL vyžadují ruční šíření a některé jiné jsou zakázány, například všechny, které by upravily distribuční sloupec. Pokus o spuštění DDL, který má nárok na automatické šíření, vyvolá chybu a ponechá tabulky v koordinačním uzlu beze změny.
Tady je odkaz na kategorie příkazů DDL, které se šíří.
Přidávání a úpravy sloupců
Azure Cosmos DB for PostgreSQL automaticky šíří většinu příkazů ALTER TABLE . Přidání sloupců nebo změna jejich výchozích hodnot funguje stejně jako v databázi PostgreSQL s jedním počítačem:
-- Adding a column
ALTER TABLE products ADD COLUMN description text;
-- Changing default value
ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
Významné změny existujícího sloupce, jako je přejmenování nebo změna jeho datového typu, jsou také v pořádku. Datový typ distribučního sloupce však nelze změnit. Tento sloupec určuje, jak se data tabulky distribuují prostřednictvím clusteru, a úprava jejich datového typu by vyžadovala přesunutí dat.
Při pokusu o to dojde k chybě:
-- 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
*/
Přidání nebo odebrání omezení
Použití služby Azure Cosmos DB for PostgreSQL umožňuje dál využívat bezpečnost relační databáze, včetně omezení databáze (viz dokumentace k PostgreSQL). Vzhledem k povaze distribuovaných systémů azure Cosmos DB for PostgreSQL nebude mezi odkazy na omezení jedinečnosti ani referenční integritu mezi pracovními uzly.
Pokud chcete nastavit cizí klíč mezi spolulokovanými distribuovanými tabulkami, vždy do klíče zahrňte distribuční sloupec. Zahrnutí distribučního sloupce může zahrnovat vytvoření složené klíče.
Cizí klíče mohou být vytvořeny v těchto situacích:
- mezi dvěma místními (nedistribuovanými) tabulkami,
- mezi dvěma referenčními tabulkami,
- mezi dvěma distribuovanými distribuovanými tabulkami, pokud klíč obsahuje distribuční sloupec, nebo
- jako distribuovaná tabulka odkazující na referenční tabulku
Cizí klíče z referenčních tabulek do distribuovaných tabulek se nepodporují.
Poznámka:
Primární klíče a omezení jedinečnosti musí obsahovat distribuční sloupec. Přidání do sloupce, který není distribuční, vygeneruje chybu.
Tento příklad ukazuje, jak vytvořit primární a cizí klíče v distribuovaných tabulkách:
--
-- 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);
Podobně zahrňte distribuční sloupec do omezení jedinečnosti:
-- 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);
Omezení typu Not-Null se dají použít u libovolného sloupce (distribuce nebo ne), protože nevyžadují žádné vyhledávání mezi pracovními procesy.
ALTER TABLE ads ALTER COLUMN image_url SET NOT NULL;
Použití NEPLATNÝch omezení
V některých situacích může být užitečné vynutit omezení pro nové řádky a zároveň umožnit, aby stávající neodpovídající řádky zůstaly beze změny. Azure Cosmos DB for PostgreSQL podporuje tuto funkci pro omezení CHECK a cizí klíče pomocí označení omezení PostgreSQL NOT VALID.
Představte si například aplikaci, která ukládá profily uživatelů do referenční tabulky.
-- 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');
V průběhu času si představte, že se do tabulky dostane několik ne adres.
INSERT INTO users VALUES
('foo@example.com'), ('hacker12@aol.com'), ('lol');
Chtěli bychom ověřit adresy, ale PostgreSQL nám obvykle neumožňuje přidat omezení CHECK, které selže pro existující řádky. Povoluje však omezení označené jako neplatné:
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;
Nové řádky jsou teď chráněné.
INSERT INTO users VALUES ('fake');
/*
ERROR: new row for relation "users_102010" violates
check constraint "syntactic_email_102010"
DETAIL: Failing row contains (fake).
*/
Později se správce databáze může během ne špičky pokusit opravit chybné řádky a obnovit omezení.
-- later, attempt to validate all rows
ALTER TABLE users
VALIDATE CONSTRAINT syntactic_email;
Dokumentace k PostgreSQL obsahuje další informace o NOT VALID a VALIDATE CONSTRAINT v části ALTER TABLE .
Přidávání a odebírání indexů
Azure Cosmos DB for PostgreSQL podporuje přidávání a odebírání indexů:
-- Adding an index
CREATE INDEX clicked_at_idx ON clicks USING BRIN (clicked_at);
-- Removing an index
DROP INDEX clicked_at_idx;
Přidání indexu přebírá zámek zápisu, který může být nežádoucí v "systémovém záznamu" s více tenanty. Pokud chcete minimalizovat výpadky aplikací, vytvořte index souběžně . Tato metoda vyžaduje větší celkovou práci než standardní sestavení indexu a dokončení trvá déle. Vzhledem k tomu, že umožňuje normální operace pokračovat během sestavování indexu, je tato metoda užitečná pro přidání nových indexů do produkčního prostředí.
-- Adding an index without locking table writes
CREATE INDEX CONCURRENTLY clicked_at_idx ON clicks USING BRIN (clicked_at);
Typy a funkce
Vytváření vlastních typů SQL a uživatelem definovaných funkcí propoguje na pracovní uzly. Vytvoření takových databázových objektů v transakci s distribuovanými operacemi však zahrnuje kompromisy.
Azure Cosmos DB for PostgreSQL paralelizuje operace, jako create_distributed_table()
jsou napříč horizontálními oddíly, pomocí více připojení na pracovní proces. Zatímco při vytváření databázového objektu ji Azure Cosmos DB for PostgreSQL rozšíří do pracovních uzlů pomocí jednoho připojení na pracovní proces. Kombinace dvou operací v jedné transakci může způsobit problémy, protože paralelní připojení nebudou moci zobrazit objekt, který byl vytvořen přes jedno připojení, ale dosud potvrzen.
Zvažte blok transakcí, který vytvoří typ, tabulku, načte data a distribuuje tabulku:
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;
Před Citus 11.0 odloží Citus vytvoření typu na pracovních uzlech a potvrdí ho samostatně při vytváření distribuované tabulky. To umožnilo paralelní kopírování create_distributed_table()
dat. Zároveň však znamenalo, že typ nebyl vždy k dispozici na pracovních uzlech Citus – nebo pokud se transakce vrátila zpět, typ by zůstal na pracovních uzlech.
U Citus 11.0 se výchozí chování mění tak, aby upřednostňovala konzistenci schématu mezi koordinátorem a pracovními uzly. Nové chování má nevýhodu: Pokud se šíření objektu stane po paralelním příkazu ve stejné transakci, transakce již nelze dokončit, jak je zvýrazněno CHYB v bloku kódu níže:
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
Pokud narazíte na tento problém, existují dvě jednoduchá alternativní řešení:
- Pomocí sady lze
citus.create_object_propagation
automatic
odložit vytvoření typu v této situaci, v takovém případě může existovat určitá nekonzistence mezi tím, které databázové objekty existují na různých uzlech. - Pomocí nastavení
citus.multi_shard_modify_mode
sequential
můžete zakázat paralelismus pro jednotlivé uzly. Načtení dat ve stejné transakci může být pomalejší.