Osvědčené postupy pro Apache Phoenix z hlediska výkonu
Nejdůležitější aspektem Apache Phoenix výkonu je optimalizace základních HBA pro Apache. Phoenix vytvoří model relačních dat základem HBA, který převede dotazy SQL na operace HBA, jako jsou například kontroly. Návrh schématu tabulky, výběr a řazení polí v primárním klíči a vaše používání indexů má vliv na výkon v Phoenixu.
Návrh schématu tabulky
Když vytvoříte tabulku v Phoenixu, tato tabulka je uložená v tabulce HBA. Tabulka HBA obsahuje skupiny sloupců (rodin sloupců), ke kterým se přistupuje dohromady. Řádek v tabulce Phoenixu je řádek v tabulce HBA, kde každý řádek obsahuje buňky s verzemi, které jsou přidružené k jednomu nebo více sloupcům. Logicky, jeden řádek HBA je kolekcí párů klíč-hodnota, z nichž každá má stejnou hodnotu rowkey. To znamená, že každá dvojice klíč-hodnota má atribut rowkey a hodnota tohoto atributu rowkey je stejná pro určitý řádek.
Návrh schématu tabulky Phoenix zahrnuje návrh primárního klíče, návrh rodiny sloupců, jednotlivý návrh sloupce a způsob rozdělení dat do oddílů.
Návrh primárního klíče
Primární klíč definovaný v tabulce v Phoenixu určuje, jak jsou data uložená v rowkey podkladové tabulky HBA. V rámci adaptérů HBA je jediným způsobem, jak získat přístup k určitému řádku, rowkey. Kromě toho jsou data uložená v tabulce HBA řazena podle rowkey. Phoenix sestaví hodnotu rowkey zřetězením hodnot každého sloupce v řádku v pořadí, v jakém jsou definovány v primárním klíči.
Například tabulka pro kontakty má jméno, příjmení, telefonní číslo a adresu, a to vše ve stejné rodině sloupců. Můžete definovat primární klíč na základě rostoucího pořadového čísla:
| rowkey | adresa | Android | firstName | lastName |
|---|---|---|---|---|
| 1000 | 1111 síť San Gabrielem Dr. | 1-425-000-0002 | John | Dole |
| 8396 | 5415 síť San Gabrielem Dr. | 1-230-555-0191 | Calvin | Raji |
Pokud se ale často dotazuje podle oprávnění lastName, nemusí tento primární klíč správně fungovat, protože každý dotaz vyžaduje, aby všechny dotazy načetly hodnotu každé příjmení. Místo toho můžete definovat primární klíč ve sloupcích lastName, firstName a číslo rodného čísla. Posledním sloupcem je nejednoznačnost dvou rezidentů na stejné adrese, jako je například otců a syn.
| rowkey | adresa | Android | firstName | lastName | socialSecurityNum |
|---|---|---|---|---|---|
| 1000 | 1111 síť San Gabrielem Dr. | 1-425-000-0002 | John | Dole | 111 |
| 8396 | 5415 síť San Gabrielem Dr. | 1-230-555-0191 | Calvin | Raji | 222 |
S tímto novým primárním klíčem klíče řádků generované v Phoenixu budou:
| rowkey | adresa | Android | firstName | lastName | socialSecurityNum |
|---|---|---|---|---|---|
| Dole – Jan až 111 | 1111 síť San Gabrielem Dr. | 1-425-000-0002 | John | Dole | 111 |
| Raji-Calvin-222 | 5415 síť San Gabrielem Dr. | 1-230-555-0191 | Calvin | Raji | 222 |
V prvním řádku výše jsou data pro rowkey reprezentovaná, jak je znázorněno níže:
| rowkey | key | hodnota |
|---|---|---|
| Dole – Jan až 111 | adresa | 1111 síť San Gabrielem Dr. |
| Dole – Jan až 111 | Android | 1-425-000-0002 |
| Dole – Jan až 111 | firstName | John |
| Dole – Jan až 111 | lastName | Dole |
| Dole – Jan až 111 | socialSecurityNum | 111 |
Tato rowkey nyní ukládá duplicitní kopii dat. Vezměte v úvahu velikost a počet sloupců, které zahrnete do primárního klíče, protože tato hodnota je zahrnutá do každé buňky v podkladové tabulce HBA.
Také pokud má primární klíč hodnoty, které se rovnoměrně zvětšující, měli byste vytvořit tabulku s kontejnery Salt , abyste se vyhnuli vytváření hotspotů pro zápis – viz data oddílu.
Návrh rodiny sloupců
Pokud jsou některé sloupce dostupné častěji než jiné, měli byste vytvořit více rodin sloupců, které oddělují často používané sloupce ze sloupců s zřídka použitou výjimkou.
Také pokud jsou k určitým sloupcům přicházet společně, umístěte tyto sloupce do stejné rodiny sloupců.
Návrh sloupce
- Ponechte sloupce VARCHAR pod přibližně 1 MB z důvodu nákladů na vstupně-výstupní operace velkých sloupců. Při zpracování dotazů vyplní materializuje buňky v plném rozsahu před jejich odesláním klientovi a klient je zaplní před tím, než ho dostanou do kódu aplikace.
- Uložte hodnoty sloupce pomocí kompaktního formátu, jako je například protobuf, Avro, msgpack nebo BSON. JSON se nedoporučuje, protože je větší.
- Zvažte komprimaci dat před úložištěm za účelem snížení latence a vstupně-výstupních nákladů.
Dělení dat
Phoenix vám umožňuje řídit počet oblastí, ve kterých jsou vaše data distribuována, což může významně zvýšit výkon čtení a zápisu. Když vytváříte tabulku v Phoenixu, můžete data buď nasoleit, nebo předem rozdělit.
Chcete-li během vytváření nasoleit tabulku, zadejte počet sad Salt:
CREATE TABLE CONTACTS (...) SALT_BUCKETS = 16
Toto nasolení rozdělí tabulku podél hodnot primárních klíčů a automaticky zvolí hodnoty.
Chcete-li určit, kde dojde k rozdělení tabulky, můžete tabulku před rozrozdělením zadáním hodnot rozsahu, podél kterých se rozdělení provádí. Chcete-li například vytvořit tabulku rozdělenou podél tří oblastí:
CREATE TABLE CONTACTS (...) SPLIT ON ('CS','EU','NA')
Návrh indexu
Index Phoenix je tabulka HBA, která ukládá kopii některých nebo všech dat z indexované tabulky. Index zvyšuje výkon pro konkrétní typy dotazů.
Pokud máte definováno více indexů a pak dotaz na tabulku, aplikace Phoenix automaticky vybere nejlepší index pro dotaz. Primární index se vytvoří automaticky v závislosti na vybraných primárních klíčích.
U předpokládaných dotazů můžete také vytvořit sekundární indexy zadáním jejich sloupců.
Při navrhování indexů:
- Vytvářejte pouze indexy, které potřebujete.
- Omezte počet indexů na často aktualizovaných tabulkách. Aktualizace tabulky se přeloží na zápisy do hlavní tabulky i tabulek indexu.
Vytváření sekundárních indexů
Sekundární indexy můžou zlepšit výkon při čtení tím, že se na základě toho, co by představovalo úplné prohledávání tabulky, provedou vyhledávání bodů, a to za cenu úložného prostoru a rychlosti zápisu. Sekundární indexy je možné přidat nebo odebrat po vytvoření tabulky a nevyžadují změny existujících dotazů – dotazy stačí spustit rychleji. V závislosti na vašich potřebách zvažte vytvoření zahrnutých indexů, funkčních indexů nebo obojího.
Použití zahrnutých indexů
Zahrnuté indexy jsou indexy, které zahrnují data z řádku kromě indexovaných hodnot. Po nalezení požadované položky indexu není nutné přístup k primární tabulce.
Například v tabulce příklad kontaktu byste mohli vytvořit sekundární index pouze v socialSecurityNum sloupci. Tento sekundární index by urychlil dotazy, které filtrují podle hodnot socialSecurityNum, ale načítání ostatních hodnot polí bude vyžadovat další čtení v hlavní tabulce.
| rowkey | adresa | Android | firstName | lastName | socialSecurityNum |
|---|---|---|---|---|---|
| Dole – Jan až 111 | 1111 síť San Gabrielem Dr. | 1-425-000-0002 | John | Dole | 111 |
| Raji-Calvin-222 | 5415 síť San Gabrielem Dr. | 1-230-555-0191 | Calvin | Raji | 222 |
Pokud ale obvykle chcete vyhledat pole firstName a lastName s daným socialSecurityNum, mohli byste vytvořit zahrnutý index, který obsahuje pole firstName a lastName jako skutečná data v tabulce index:
CREATE INDEX ssn_idx ON CONTACTS (socialSecurityNum) INCLUDE(firstName, lastName);
Tento zahrnutý index umožňuje, aby následující dotaz získal všechna data pouhým čtením z tabulky obsahující sekundární index:
SELECT socialSecurityNum, firstName, lastName FROM CONTACTS WHERE socialSecurityNum > 100;
Použití funkčních indexů
Funkční indexy umožňují vytvořit index pro libovolný výraz, který očekáváte, že se bude používat v dotazech. Jakmile budete mít funkční index a dotaz použije tento výraz, může se index použít k načtení výsledků, nikoli k tabulce dat.
Můžete například vytvořit index, který vám umožní provádět hledání bez rozlišování velkých a malých písmen na základě kombinovaného křestního jména a příjmení osoby:
CREATE INDEX FULLNAME_UPPER_IDX ON "Contacts" (UPPER("firstName"||' '||"lastName"));
Návrh dotazu
Hlavními hledisky při návrhu dotazů jsou:
- Pochopení plánu dotazů a ověření očekávaného chování.
- Připojte se efektivně.
Pochopení plánu dotazu
V SQLLinepoužijte vysvětlení následovaný vaším dotazem SQL k zobrazení plánu operací, které bude provádět Phoenix. Ověřte, že plán:
- V případě potřeby použije primární klíč.
- Používá vhodné sekundární indexy místo tabulky dat.
- Nástroj používá kontrolu rozsahu nebo PŘESKOČENí kontroly, kdykoli je to možné, nikoli při prohledávání tabulky.
Příklady plánů
Řekněme například, že máte tabulku s názvem lety, která ukládá informace o zpoždění letu.
Pokud chcete vybrat všechny lety s airlineid 19805 , kde airlineid je pole, které není v primárním klíči nebo v žádném indexu:
select * from "FLIGHTS" where airlineid = '19805';
Spusťte příkaz vysvětlit následujícím způsobem:
explain select * from "FLIGHTS" where airlineid = '19805';
Plán dotazu vypadá takto:
CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER FLIGHTS
SERVER FILTER BY AIRLINEID = '19805'
V tomto plánu si poznamenejte frázi úplná kontrola nad lety. Tato fráze indikuje, že při provádění se v tabulce prohledává všechny řádky v tabulce místo použití možnosti zefektivnit kontrolu rozsahu nebo přeskočit kontrolu.
Nyní řekněme, že chcete zadat dotaz na lety 2. ledna 2014 pro přepravce, AA kde jeho flightnum bylo větší než 1. Řekněme, že sloupce year, month, DayOfMonth, přepravce a flightnum existují v tabulce příkladů a jsou všechny součástí složeného primárního klíče. Dotaz by vypadal takto:
select * from "FLIGHTS" where year = 2014 and month = 1 and dayofmonth = 2 and carrier = 'AA' and flightnum > 1;
Podívejme se na plán tohoto dotazu:
explain select * from "FLIGHTS" where year = 2014 and month = 1 and dayofmonth = 2 and carrier = 'AA' and flightnum > 1;
Výsledný plán:
CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER FLIGHTS [2014,1,2,'AA',2] - [2014,1,2,'AA',*]
Hodnoty v hranatých závorkách jsou rozsahem hodnot pro primární klíče. V tomto případě jsou hodnoty rozsahu opraveny s rokem 2014, měsíc 1 a DayOfMonth 2, ale umožňují hodnoty pro flightnum počínaje 2 a na začátku ( * ). Tento plán dotazu potvrdí, že se primární klíč používá podle očekávání.
Dále v tabulce lety vytvořte index s názvem carrier2_idx , který je pouze v poli přepravce. Tento index zahrnuje také flightdate, tailnum, Origin a flightnum jako zahrnuté sloupce, jejichž data jsou také uložená v indexu.
CREATE INDEX carrier2_idx ON FLIGHTS (carrier) INCLUDE(FLIGHTDATE,TAILNUM,ORIGIN,FLIGHTNUM);
Řekněme, že chcete získat přepravce spolu s flightdate a tailnum, jak je znázorněno v následujícím dotazu:
explain select carrier,flightdate,tailnum from "FLIGHTS" where carrier = 'AA';
Měli byste vidět, že se používá tento index:
CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER CARRIER2_IDX ['AA']
Úplný seznam položek, které se mohou objevit v tématu Vysvětlení výsledků plánu, najdete v části vysvětlující plány v příručce pro ladění Apache Phoenix.
Efektivní připojení
Obecně platí, že chcete vyhnout spojení, pokud jedna strana není malá, zejména u častých dotazů.
V případě potřeby můžete s pomocným nástrojem provádět velké spojení /*+ USE_SORT_MERGE_JOIN */ , ale velký počet spojení je náročná operace nad velkým počtem řádků. Pokud celková velikost všech tabulek na pravé straně by překročila dostupnou paměť, použijte /*+ NO_STAR_JOIN */ pomocný parametr.
Scénáře
Následující pokyny popisují některé běžné vzory.
Čtení – těžké úlohy
Pro případy použití s vysokým využitím se ujistěte, že používáte indexy. Kromě toho, pokud chcete ušetřit režijní náklady při čtení, zvažte vytvoření zahrnutých indexů.
Zátěžové úlohy náročné na zápis
Pro úlohy náročné na zápis, u kterých je primární klíč rovnoměrně zvětšující, vytvořte bloky Salt, které vám pomůžou vyhnout se psaní hotspotů, a to za cenu celkové propustnosti čtení z důvodu dalších potřebných kontrol. Také při použití UPSERT k zápisu velkého počtu záznamů vypněte automatické potvrzení a dávkujte záznamy.
Hromadné odstranění
Při odstraňování velkých datových sad zapněte funkci autocommit před vydáním dotazu DELETE, aby klient nemusel pamatovat klíče řádků pro všechny odstraněné řádky. Automatický zápis znemožňuje klientovi ukládat do vyrovnávací paměti řádky ovlivněné ODSTRANĚNÍm, aby je mohl v Phoenixu odstranit přímo na serverech oblastí bez nutnosti jejich vrácení klientovi.
Unmutable a pouze připojení
Pokud váš scénář přinese rychlost zápisu přes integritu dat, zvažte možnost zakázat protokol zápisu při vytváření tabulek:
CREATE TABLE CONTACTS (...) DISABLE_WAL=true;
Podrobnosti o této a dalších možnostech najdete v tématu Apache Phoenix gramatiky.