sql >> Databáze >  >> RDS >> PostgreSQL

Pokročilé párování oddílů pro spojení po oddílech

Dříve jsem psal blog o připojení po oddílech v PostgreSQL. V tomto blogu jsem mluvil o pokročilé technice přiřazování oddílů, která umožní použít spojení po oddílech ve více případech. V tomto blogu tuto techniku ​​podrobně probereme.

Abychom to zrekapitulovali, základní technika porovnávání oddílů umožňuje provést spojení mezi dvěma rozdělenými tabulkami pomocí techniky spojování po oddílech, pokud mají dvě rozdělené tabulky přesně odpovídající hranice oddílů, např. rozdělené tabulky prt1 a prt2 popsané níže

psql> \d+ prt1
... [output clipped]
Partition key: RANGE (a)
Partitions: prt1_p1 FOR VALUES FROM (0) TO (5000),
prt1_p2 FOR VALUES FROM (5000) TO (15000),
prt1_p3 FOR VALUES FROM (15000) TO (30000)

a

psql>\d+ prt2
... [ output clipped ]
Partition key: RANGE (b)
Partitions: prt2_p1 FOR VALUES FROM (0) TO (5000),
prt2_p2 FOR VALUES FROM (5000) TO (15000),
prt2_p3 FOR VALUES FROM (15000) TO (30000)

Spojení mezi prt1 a prt2 v jejich klíči oddílu (a) je rozděleno na spojení mezi jejich odpovídajícími oddíly, tj. prt1_p1 spojuje prt2_p1, prt1_p2 spojuje prt2_p2 a prt1_p3 spojuje prt2_p3. Výsledky těchto tří spojení tvoří výsledek spojení mezi prt1 a prt2. To má mnoho výhod, jak jsem uvedl v mém předchozím blogu. Základní párování oddílů však nemůže spojit dvě rozdělené tabulky s různými hranicemi oddílů. Pokud má prt1 ve výše uvedeném příkladu další oddíl prt1_p4 PRO HODNOTY OD (30000) DO (50000), základní porovnávání oddílů by nepomohlo převést spojení mezi  prt1 a prt2 na spojení podle oddílu, protože nemají přesně odpovídající oddíl hranice.

Mnoho aplikací používá oddíly k oddělení aktivně používaných dat a zastaralých dat, což je technika, o které jsem hovořil ve svém jiném blogu. Zastaralá data jsou nakonec odstraněna zrušením oddílů. Jsou vytvořeny nové oddíly, aby mohly obsahovat nová data. Spojení mezi dvěma takto rozdělenými tabulkami bude většinou používat spojení po oddílech, protože většinu času budou mít odpovídající oddíly. Ale když se do jedné z těchto tabulek přidá aktivní oddíl nebo se smaže zastaralý oddíl, jejich hranice oddílu se nebudou shodovat, dokud druhá tabulka také neprojde podobnou operací. Během tohoto intervalu spojení mezi těmito dvěma tabulkami nebude používat spojení po oddílech a jeho provedení může trvat neobvykle déle. Nechceme, aby spojení zasahující do databáze během tohoto krátkého trvání fungovalo špatně, protože nelze použít spojení po oddílech. Pokročilý algoritmus porovnávání oddílů pomáhá v tomto a složitějších případech, kdy se hranice oddílů přesně neshodují.

Pokročilý algoritmus porovnávání oddílů

Pokročilá technika porovnávání oddílů najde odpovídající oddíly ze dvou rozdělených tabulek, i když se jejich hranice oddílů přesně neshodují. Najde odpovídající oddíly porovnáním hranic z obou tabulek v jejich seřazeném pořadí podobném algoritmu spojení sloučení. Jakékoli dva oddíly, jeden z každé rozdělené tabulky, jejichž hranice se přesně shodují nebo se překrývají, jsou považovány za spojující se partnery, protože mohou obsahovat spojující se řádky. Pokračujeme ve výše uvedeném příkladu a řekněme, že se do prt4 přidá aktivní nový oddíl prt2_p4. Rozdělené tabulky nyní vypadají takto:

psql>\d+ prt1
... [output clipped]
Partition key: RANGE (a)
Partitions: prt1_p1 FOR VALUES FROM (0) TO (5000),
prt1_p2 FOR VALUES FROM (5000) TO (15000),
prt1_p3 FOR VALUES FROM (15000) TO (30000)

a

psql>\d+ prt2
... [ output clipped ]
Partition key: RANGE (b)
Partitions: prt2_p1 FOR VALUES FROM (0) TO (5000),
prt2_p2 FOR VALUES FROM (5000) TO (15000),
prt2_p3 FOR VALUES FROM (15000) TO (30000),
prt2_p4 FOR VALUES FROM (30000) TO (50000)

Je snadné vidět, že hranice oddílů prt1_p1 a prt2_p1, prt1_p2 a prt2_p2 a prt1_p3 a prt2_p3 si odpovídají. Ale na rozdíl od základního párování oddílů, pokročilé párování oddílů bude vědět, že prt2_p4 nemá žádný odpovídající oddíl v prt1. Pokud je spojení mezi prt1 a prt2 VNITŘNÍ spojení nebo když je prt2 ve spojení VNITŘNÍ relací, výsledek spojení nebude mít žádný řádek z prt2_p4. Optimalizátor dotazů s aktivovanými podrobnými informacemi o odpovídajících oddílech a oddílech, které se neshodují, pouze proti tomu, zda se hranice oddílu shodují či nikoli, může rozhodnout, zda použít spojení po oddílech či nikoli. V tomto případě zvolí provedení spojení jako spojení mezi odpovídajícími oddíly a ponechá prt2_p4 stranou. Ale to není moc jako „pokročilé“ párování oddílů. Podívejme se tentokrát na trochu komplikovanější případ s použitím seznamů rozdělených tabulek:

psql>\d+ plt1
Partition key: LIST (c)
Partitions: plt1_p1 FOR VALUES IN ('0001', '0003'),
plt1_p2 FOR VALUES IN ('0004', '0006'),
plt1_p3 FOR VALUES IN ('0008', '0009')

a

psql>\d+ plt2
Partition key: LIST (c)
Partitions: plt2_p1 FOR VALUES IN ('0002', '0003'),
plt2_p2 FOR VALUES IN ('0004', '0006'),
plt2_p3 FOR VALUES IN ('0007', '0009')

Všimněte si, že v obou relacích jsou přesně tři oddíly, ale seznamy hodnot oddílů se liší. Seznam odpovídající oddílu plt1_p2 přesně odpovídá seznamu plt2_p2. Kromě toho žádné dva oddíly, jeden z obou stran, nemají přesně odpovídající seznamy. Pokročilý algoritmus porovnávání oddílů vyvozuje, že plt1_p1 a plt2_p1 mají překrývající se seznamy a jejich seznamy se nepřekrývají s žádným jiným oddílem z jiného vztahu. Podobně pro plt1_p3 a plt2_p3. Optimalizátor dotazů pak zjistí, že spojení mezi plt1 a plt2 lze provést jako spojení po oddílech spojením odpovídajících oddílů, tj. plt1_p1 a plt2_p1, plt1_p2 a plt2_p2, respektive plt1_p3 a plt2_p3. Algoritmus dokáže najít odpovídající oddíly v ještě složitějších sadách seznamů vázaných na oddíly a také v tabulkách rozdělených podle rozsahu. Pro stručnost se jim ale nebudeme věnovat. Zainteresovaní a odvážnější čtenáři se mohou podívat na commit. Má také mnoho testovacích případů, které ukazují různé scénáře, kde se používá pokročilý algoritmus porovnávání oddílů.

Omezení

Vnější spojení s chybějícími odpovídajícími oddíly na vnitřní straně

Vnější spojení představují zvláštní problém ve světě PostgreSQL. Zvažte prt2 LEFT JOIN prt1 ve výše uvedeném příkladu, kde prt2 je VNĚJŠÍ vztah. prt2_p4 nemá spojovacího partnera v prt1 a přesto by řádky v tomto oddílu měly být součástí výsledku spojení, protože patří k vnějšímu vztahu. V PostgreSQL, když je VNITŘNÍ strana spojení prázdná, je reprezentována „fiktivním“ vztahem, který negeneruje žádné řádky, ale stále zná schéma tohoto vztahu. Obvykle se "fiktivní" vztah objeví z nefiktivního vztahu, který nebude vydávat žádné řádky kvůli určité optimalizaci dotazu, jako je vyloučení omezení. Optimalizátor dotazů PostgreSQL označí takový nefiktivní vztah jako fiktivní a exekutor při provádění takového spojení pokračuje normálně. Ale když neexistuje žádný odpovídající vnitřní oddíl pro vnější oddíl, neexistuje žádná „existující entita“, kterou lze označit jako „figurínu“. Například v tomto případě neexistuje žádný prt1_p4, který by mohl představovat fiktivní vnitřní oddíl spojující vnější prt2_p4. Právě teď PostgreSQL nemá způsob, jak „vytvořit“ takové „fiktivní“ vztahy během plánování. Optimalizátor dotazů proto v tomto případě nepoužívá spojení po oddílech.

V ideálním případě takové spojení s prázdným vnitřním vyžaduje pouze schéma vnitřního vztahu a ne celý vztah. Toto schéma lze odvodit ze samotné dělené tabulky. Vše, co potřebuje, je schopnost vytvořit spojovací řádek pomocí sloupců z řádku na vnější straně spojených hodnotami NULL pro sloupce z vnitřní strany. Jakmile budeme mít tuto možnost v PostgreSQL, bude optimalizátor dotazů schopen používat spojení po oddílech i v těchto případech.

Dovolte mi zdůraznit, že vnější spojení, kde na vnitřním spojení nechybí žádné oddíly, používají spojení po oddílech.

Více odpovídajících oddílů

Jsou-li tabulky rozděleny tak, že více oddílů na jedné straně odpovídá jednomu nebo více oddílům na druhé straně, nelze spojení po oddílech použít, protože neexistuje způsob, jak během plánování vyvolat vztah „Připojit“, který představuje dva nebo více oddíly dohromady. Doufejme, že toto omezení také někdy odstraníme a umožníme použití spojování podle oddílů i v těchto případech.

Hash rozdělené tabulky

Hranice oddílů dvou hašovaných dělených tabulek používajících stejné modulo se vždy shodují. Když je modulo odlišné, řádek z daného oddílu jedné tabulky může mít své spojující partnery v mnoha oddílech druhé tabulky, takže daný oddíl na jedné straně odpovídá více oddílům druhé tabulky, takže spojení po oddílech je neúčinné.

Když se pokročilému algoritmu pro párování oddílů nepodaří najít odpovídající oddíly nebo nelze použít spojení po oddílech kvůli výše uvedeným omezením, PostgreSQL se vrátí a spojí rozdělené tabulky jako běžné tabulky.

Pokročilý čas shody oddílu

Když Simon komentoval tuto funkci, zmínil zajímavou věc. Oddíly rozdělené tabulky se často nemění, takže výsledek pokročilého párování oddílů by měl zůstat stejný po delší dobu. Počítat jej pokaždé, když je proveden dotaz zahrnující tyto tabulky, je zbytečné. Místo toho bychom mohli uložit sadu odpovídajících oddílů do nějakého katalogu a obnovit ji pokaždé, když se oddíly změní. Je to trochu práce, ale stojí to za čas strávený přiřazováním oddílu pro každý dotaz.

I přes všechna tato omezení je to, co dnes máme, velmi užitečné řešení, které slouží většině praktických případů. Netřeba dodávat, že tato funkce bezproblémově funguje s FDW join push down a zlepšuje možnosti shardingu, které PostgreSQL již má!


  1. PL/SQL program pro tisk údajů o zaměstnanci

  2. Jak vytvořit tabulku v zobrazení datového listu v Accessu 2016

  3. Uložená procedura, která exportuje data do souborů csv, exportuje pouze do jednoho souboru

  4. Proč jsou v hodnotách sloupce IDENTITY mezery?