Az Apache Phoenix teljesítményével kapcsolatos ajánlott eljárások

Az Apache Phoenix teljesítményének legfontosabb eleme a mögöttes Apache HBase optimalizálása. A Phoenix létrehoz egy relációs adatmodellt a HBase-en, amely az SQL-lekérdezéseket HBase-műveletekké alakítja, például vizsgálatokká. A táblaséma kialakítása, az elsődleges kulcs mezőinek kijelölése és sorrendje, valamint az indexek használata mind hatással van a Phoenix teljesítményére.

Táblaséma tervezése

Amikor létrehoz egy táblát a Phoenixben, a rendszer egy HBase-táblában tárolja a táblát. A HBase-tábla olyan oszlopcsoportokat (oszlopcsaládokat) tartalmaz, amelyek együtt érhetők el. A Phoenix-tábla egy sora a HBase táblában, ahol minden sor egy vagy több oszlophoz társított verziószámozott cellákból áll. Logikailag egyetlen HBase-sor kulcs-érték párok gyűjteménye, amelyek mindegyike ugyanazzal a sorkulcs-értékkel rendelkezik. Vagyis minden kulcs-érték pár rendelkezik egy sorkulcs attribútummal, és a sorkulcs attribútum értéke megegyezik egy adott soréval.

A Phoenix-tábla sématervében szerepel az elsődleges kulcs kialakítása, az oszlopcsalád kialakítása, az egyes oszlopok tervezése és az adatok particionálása.

Elsődleges kulcs tervezése

A Phoenixben egy táblában definiált elsődleges kulcs határozza meg az adatok tárolásának módját a mögöttes HBase-tábla sorkulcsában. A HBase-ben csak a sorkulcs használatával lehet elérni egy adott sort. Emellett a HBase-táblákban tárolt adatokat a sorkulcs rendezi. A Phoenix a sorkulcs értékét úgy hozza létre, hogy összefűzi a sor egyes oszlopainak értékeit az elsődleges kulcsban meghatározott sorrendben.

Egy névjegytáblában például az utónév, a vezetéknév, a telefonszám és a cím szerepel, mind ugyanabban az oszlopcsaládban. Az elsődleges kulcsot egy növekvő sorszám alapján határozhatja meg:

sorkulcs Cím telefon firstName lastName
1000 1111 San Gabriel Dr. 1-425-000-0002 John Dole
8396 5415 San Gabriel Dr. 1-230-555-0191 Calvin Raji

Ha azonban gyakran kérdezi le a lastName függvényt, előfordulhat, hogy ez az elsődleges kulcs nem működik megfelelően, mivel minden lekérdezéshez teljes táblavizsgálat szükséges az összes lastName értékének olvasásához. Ehelyett megadhat egy elsődleges kulcsot a lastName, a firstName és a társadalombiztosítási szám oszlopban. Ez az utolsó oszlop két, azonos nevű lakcímen lévő lakót, például egy apát és egy fiút egyértelműsít.

sorkulcs Cím telefon firstName lastName socialSecurityNum
1000 1111 San Gabriel Dr. 1-425-000-0002 John Dole 111
8396 5415 San Gabriel Dr. 1-230-555-0191 Calvin Raji 222

Ezzel az új elsődleges kulccsal a Phoenix által létrehozott sorkulcsok a következőek:

sorkulcs Cím telefon firstName lastName socialSecurityNum
Dole-John-111 1111 San Gabriel Dr. 1-425-000-0002 John Dole 111
Raji-Calvin-222 5415 San Gabriel Dr. 1-230-555-0191 Calvin Raji 222

A megadott tábla első sorában a sorkulcs adatai az alábbi módon jelennek meg:

sorkulcs kulcs Érték
Dole-John-111 Cím 1111 San Gabriel Dr.
Dole-John-111 telefon 1-425-000-0002
Dole-John-111 firstName John
Dole-John-111 lastName Dole
Dole-John-111 socialSecurityNum 111

Ez a sorkulcs mostantól az adatok másolatát tárolja. Vegye figyelembe az elsődleges kulcsban szereplő oszlopok méretét és számát, mert ez az érték a mögöttes HBase-tábla minden celláját tartalmazza.

Ha az elsődleges kulcs monoton módon növekvő értékekkel rendelkezik, sógyűjtőkkel kell létrehoznia a táblát, hogy elkerülje az írási pontok létrehozását – lásd: Partícióadatok.

Oszlopcsalád kialakítása

Ha egyes oszlopokhoz gyakrabban férnek hozzá, mint mások, több oszlopcsaládot kell létrehoznia, hogy elkülönítse a gyakran használt oszlopokat a ritkán használt oszlopoktól.

Ha bizonyos oszlopok általában együtt érhetők el, helyezze ezeket az oszlopokat ugyanabba az oszlopcsaládba.

Oszlopterv

  • Tartsa a VARCHAR oszlopokat körülbelül 1 MB alatt a nagy oszlopok I/O-költségei miatt. A lekérdezések feldolgozásakor a HBase teljes mértékben materializálja a cellákat, mielőtt elküldené őket az ügyfélnek, és az ügyfél teljes egészében megkapja őket, mielőtt átadja őket az alkalmazás kódjának.
  • Az oszlopértékeket kompakt formátumban tárolhatja, például protobuf, Avro, msgpack vagy BSON használatával. A JSON nem ajánlott, mivel nagyobb.
  • A késés és az I/O-költségek csökkentése érdekében fontolja meg az adatok tárolási előtti tömörítését.

Partícióadatok

A Phoenix lehetővé teszi az adatok terjesztésének régióinak számát, ami jelentősen növelheti az olvasási/írási teljesítményt. Phoenix-tábla létrehozásakor sózhatja vagy előre feloszthatja az adatokat.

Ha a létrehozás során sót szeretne sót adni egy táblához, adja meg a sógyűjtők számát:

CREATE TABLE CONTACTS (...) SALT_BUCKETS = 16

Ez a sózás felosztja a táblát az elsődleges kulcsok értékei mentén, és automatikusan kiválasztja az értékeket.

A táblázat felosztási helyét előre feloszthatja úgy, hogy megadja azokat a tartományértékeket, amelyek mentén a felosztás történik. Ha például három régióra osztott táblát szeretne létrehozni:

CREATE TABLE CONTACTS (...) SPLIT ON ('CS','EU','NA')

Index kialakítása

A Phoenix-index egy HBase-tábla, amely az indexelt táblából származó adatok egy vagy több másolatát tárolja. Az index javítja bizonyos típusú lekérdezések teljesítményét.

Ha több index van definiálva, majd lekérdez egy táblát, a Phoenix automatikusan kiválasztja a lekérdezéshez legjobb indexet. A rendszer automatikusan létrehozza az elsődleges indexet a kiválasztott elsődleges kulcsok alapján.

A várt lekérdezésekhez másodlagos indexeket is létrehozhat az oszlopok megadásával.

Az indexek tervezésekor:

  • Csak a szükséges indexeket hozza létre.
  • A gyakran frissített táblák indexeinek számának korlátozása. Frissítések egy táblába a főtáblára és az indextáblákra is lefordítja az írásokat.

Másodlagos indexek létrehozása

A másodlagos indexek növelhetik az olvasási teljesítményt azáltal, hogy pontkereséssé alakítják a teljes táblavizsgálatot a tárterület és az írási sebesség költségén. A másodlagos indexek hozzáadhatók vagy eltávolíthatók a tábla létrehozása után, és nem igényelnek módosításokat a meglévő lekérdezésekben – a lekérdezések csak gyorsabban futnak. Az igényeitől függően érdemes lehet fedett indexeket, funkcionális indexeket vagy mindkettőt létrehozni.

Fedett indexek használata

A lefedett indexek olyan indexek, amelyek az indexelt értékek mellett a sorból származó adatokat is tartalmazzák. A kívánt indexbejegyzés megkeresése után nincs szükség az elsődleges táblához való hozzáférésre.

A példakapcsolati táblában például létrehozhat egy másodlagos indexet csak a socialSecurityNum oszlopban. Ez a másodlagos index felgyorsítaná a socialSecurityNum értékek alapján szűrt lekérdezéseket, de a többi mezőérték lekéréséhez további olvasásra van szükség a főtáblán.

sorkulcs Cím telefon firstName lastName socialSecurityNum
Dole-John-111 1111 San Gabriel Dr. 1-425-000-0002 John Dole 111
Raji-Calvin-222 5415 San Gabriel Dr. 1-230-555-0191 Calvin Raji 222

Ha azonban általában a socialSecurityNum alapján szeretné megkeresni a firstName és a lastName nevet, létrehozhat egy fedett indexet, amely a firstName és a lastName értéket tartalmazza tényleges adatokként az indextáblában:

CREATE INDEX ssn_idx ON CONTACTS (socialSecurityNum) INCLUDE(firstName, lastName);

Ez a lefedett index lehetővé teszi, hogy a következő lekérdezés csak a másodlagos indexet tartalmazó táblából olvasva szerezze be az összes adatot:

SELECT socialSecurityNum, firstName, lastName FROM CONTACTS WHERE socialSecurityNum > 100;

Funkcionális indexek használata

A funkcionális indexek lehetővé teszik, hogy indexet hozzon létre egy tetszőleges kifejezésen, amelyet várhatóan használni fog a lekérdezésekben. Ha már működik egy funkcionális index, és egy lekérdezés ezt a kifejezést használja, az index az adattábla helyett az eredmények lekérésére használható.

Létrehozhat például egy indexet, amely lehetővé teszi, hogy kis- és nagybetűk közötti keresést végezzen egy személy kombinált utónevén és vezetéknevén:

CREATE INDEX FULLNAME_UPPER_IDX ON "Contacts" (UPPER("firstName"||' '||"lastName"));

Lekérdezések tervezése

A lekérdezéstervezés fő szempontjai a következők:

  • Ismerje meg a lekérdezési tervet, és ellenőrizze a várt viselkedést.
  • Csatlakozás hatékonyan.

A lekérdezési terv ismertetése

Az SQLLine-ban az EXPLAIN és az SQL-lekérdezés használatával tekintheti meg a Phoenix által végrehajtott műveletek tervét. Ellenőrizze, hogy a csomag:

  • Szükség esetén az elsődleges kulcsot használja.
  • Az adattábla helyett a megfelelő másodlagos indexeket használja.
  • A TÁBLÁZATOS VIZSGÁLAT helyett a RANGE SCAN vagy a SKIP SCAN függvényt használja, amikor csak lehetséges.

Példák tervezése

Tegyük fel például, hogy van egy FLIGHTS nevű táblája, amely a járatkésés adatait tárolja.

Az összes olyan járat airlineid kiválasztásához, amelynek egy adottja 19805van, ahol airlineid egy olyan mező van, amely nem szerepel az elsődleges kulcsban vagy egy indexben:

select * from "FLIGHTS" where airlineid = '19805';

Futtassa a magyarázott parancsot az alábbiak szerint:

explain select * from "FLIGHTS" where airlineid = '19805';

A lekérdezési terv a következőképpen néz ki:

CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER FLIGHTS
   SERVER FILTER BY AIRLINEID = '19805'

Ebben a tervben jegyezze fel a TELJES VIZSGÁLAT A JÁRATOK FELETT kifejezést. Ez a kifejezés azt jelzi, hogy a tábla összes sorában a TABLE SCAN parancsot hajtja végre a hatékonyabb RANGE SCAN vagy SKIP SCAN beállítás használata helyett.

Tegyük fel, hogy 2014. január 2-án le szeretné kérdezni a 2014. január 2-i járatokat arra a fuvarozóra AA vonatkozóan, ahol a járatszám nagyobb volt, mint 1. Tegyük fel, hogy az év, hónap, napofóm, szállító és flightnum oszlop szerepel a példatáblában, és mind az összetett elsődleges kulcs része. A lekérdezés a következőképpen nézne ki:

select * from "FLIGHTS" where year = 2014 and month = 1 and dayofmonth = 2 and carrier = 'AA' and flightnum > 1;

Vizsgáljuk meg a lekérdezés tervét a következőkkel:

explain select * from "FLIGHTS" where year = 2014 and month = 1 and dayofmonth = 2 and carrier = 'AA' and flightnum > 1;

Az eredményként kapott terv a következő:

CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER FLIGHTS [2014,1,2,'AA',2] - [2014,1,2,'AA',*]

A szögletes zárójelek értékei az elsődleges kulcsok értékeinek tartományai. Ebben az esetben a tartományértékek a 2014-es év, az 1. hónap és a 2. napfónapos értékekkel vannak rögzítve, de engedélyezik a 2-vel kezdődő és a felfelé (*) kezdődő flightnum értékeket. Ez a lekérdezési terv megerősíti, hogy az elsődleges kulcs a várt módon van használatban.

Ezután hozzon létre egy indexet a FLIGHTS táblában carrier2_idx , amely csak a szállítómezőben található. Ez az index magában foglalja flightdatea , tailnum, originés flightnum fedett oszlopokat is, amelyek adatait az index is tárolja.

CREATE INDEX carrier2_idx ON FLIGHTS (carrier) INCLUDE(FLIGHTDATE,TAILNUM,ORIGIN,FLIGHTNUM);

Tegyük fel, hogy le szeretné szerezni a szolgáltatót a flightdatetailnumkövetkező lekérdezéshez hasonlóan:

explain select carrier,flightdate,tailnum from "FLIGHTS" where carrier = 'AA';

A következő indexet kell használnia:

CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER CARRIER2_IDX ['AA']

A magyarázó terv eredményei között megjelenő elemek teljes listájáért tekintse meg az Apache Phoenix hangolási útmutatójának Tervek magyarázata szakaszát.

Csatlakozás hatékonyan

Általában el szeretné kerülni az illesztéseket, kivéve, ha az egyik oldal kicsi, különösen a gyakori lekérdezések esetén.

Ha szükséges, nagy illesztéseket végezhet a /*+ USE_SORT_MERGE_JOIN */ tippel, de a nagy illesztés költséges művelet nagyszámú soron keresztül. Ha az összes jobb oldali tábla teljes mérete meghaladja a rendelkezésre álló memóriát, használja a /*+ NO_STAR_JOIN */ tippet.

Forgatókönyvek

Az alábbi irányelvek néhány gyakori mintát ismertetnek.

Írásvédett számítási feladatok

Írásvédett használati esetek esetén győződjön meg arról, hogy indexeket használ. Emellett az olvasási idő többletterhelésének mentéséhez érdemes lehet fedett indexeket létrehozni.

Írási terhelésű számítási feladatok

Olyan írási terhelések esetén, ahol az elsődleges kulcs monoton módon növekszik, hozzon létre sógyűjtőket az írási pontok elkerülése érdekében, az általános olvasási sebesség rovására a további szükséges vizsgálatok miatt. Emellett ha a UP Standard kiadás RT függvényt nagy számú rekord írásához használja, kapcsolja ki az automatikus kiküldést, és kötegelje fel a rekordokat.

Tömeges törlés

Nagy adatkészlet törlésekor a DELETE lekérdezés kiadása előtt kapcsolja be az automatikus üzenetküldést, hogy az ügyfélnek ne kelljen emlékeznie az összes törölt sor sorkulcsára. Az AutoCommit megakadályozza, hogy az ügyfél pufferelje a DELETE által érintett sorokat, hogy a Phoenix közvetlenül a régiókiszolgálókon törölje őket anélkül, hogy azokat visszaküldi az ügyfélnek.

Nem módosítható és csak hozzáfűzhető

Ha a forgatókönyv az adatintegritással szemben előnyben részesíti az írási sebességet, fontolja meg az előreírási napló letiltását a táblák létrehozásakor:

CREATE TABLE CONTACTS (...) DISABLE_WAL=true;

Erről és más lehetőségekről az Apache Phoenix Grammar című témakörben olvashat bővebben.

További lépések