Az Indexelés áttekintése az Azure Cosmos DB-ben

A KÖVETKEZŐKRE VONATKOZIK: Nosql MongoDB Cassandra Gremlin Táblázat

Az Azure Cosmos DB egy séma-agnosztikus adatbázis, amely lehetővé teszi az alkalmazás iterálását anélkül, hogy sémával vagy indexkezeléssel kellene foglalkoznia. Alapértelmezés szerint az Azure Cosmos DB automatikusan indexeli a tároló összes elemének minden tulajdonságát anélkül, hogy sémát kellene definiálnia vagy másodlagos indexeket kellene konfigurálnia.

A cikk célja annak ismertetése, hogy az Azure Cosmos DB hogyan indexeli az adatokat, illetve hogy miként használja az indexeket a lekérdezési teljesítmény javításához. Javasoljuk, hogy az indexelési szabályzatok testreszabása előtt tekintse át ezt a szakaszt.

Elemektől a fákig

Minden alkalommal, amikor egy elem tárolóban van tárolva, annak tartalma JSON-dokumentumként lesz kivetítve, majd faábrázolássá alakul. Ez az átalakítás azt jelenti, hogy az elem minden tulajdonsága csomópontként jelenik meg egy fában. A rendszer egy álgyökércsomópontot hoz létre az elem összes első szintű tulajdonságának szülőjeként. A levélcsomópontok tartalmazzák az elem által hordozott tényleges skaláris értékeket.

Vegyük például ezt az elemet:

{
  "locations": [
    { "country": "Germany", "city": "Berlin" },
    { "country": "France", "city": "Paris" }
  ],
  "headquarters": { "country": "Belgium", "employees": 250 },
  "exports": [
    { "city": "Moscow" },
    { "city": "Athens" }
  ]
}

Ez a fa a példa JSON-elemet jelöli:

Az előző, faként ábrázolt JSON-elem diagramja.

Figyelje meg, hogy a tömbök hogyan vannak kódolva a fában: egy tömb minden bejegyzése egy köztes csomópontot kap, amely a tömbben lévő bejegyzés indexével van megjelölve (0, 1 stb.).

Fáktól a tulajdonságútvonalakig

Az Azure Cosmos DB azért alakít át elemeket fákká, mert lehetővé teszi a rendszer számára, hogy a fákon belüli elérési útjukkal hivatkozzon a tulajdonságokra. Egy tulajdonság elérési útjának lekéréséhez a gyökércsomóponttól az adott tulajdonságig bejárhatjuk a fát, és összefűzhetjük az egyes bejárt csomópontok címkéit.

A korábban ismertetett példaelem minden tulajdonságának elérési útjai:

  • /locations/0/country: "Németország"
  • /locations/0/city: "Berlin"
  • /locations/1/country: "Franciaország"
  • /locations/1/city: "Párizs"
  • /headquarters/country: "Belgium"
  • /headquarters/employees: 250
  • /exports/0/city: "Moszkva"
  • /exports/1/city: "Athén"

Az Azure Cosmos DB hatékonyan indexeli az egyes tulajdonságok elérési útját és annak megfelelő értékét egy elem írásakor.

Indextípusok

Az Azure Cosmos DB jelenleg három indextípust támogat. Ezeket az indextípusokat az indexelési szabályzat definiálásakor konfigurálhatja.

Tartományindex

A tartományindexek rendezett faszerű szerkezeten alapulnak. A tartományindex típusa a következőhöz használatos:

  • Egyenlőségi lekérdezések:

    SELECT * FROM container c WHERE c.property = 'value'
    
    SELECT * FROM c WHERE c.property IN ("value1", "value2", "value3")
    
  • Egyenlőségegyezés tömbelemen

    SELECT * FROM c WHERE ARRAY_CONTAINS(c.tags, "tag1")
    
  • Tartomány lekérdezései:

    SELECT * FROM container c WHERE c.property > 'value'
    

    Megjegyzés

    (a következőhöz >működik: , <, >=, <=) !=

  • Tulajdonság meglétének ellenőrzése:

    SELECT * FROM c WHERE IS_DEFINED(c.property)
    
  • Sztringrendszerfüggvények:

    SELECT * FROM c WHERE CONTAINS(c.property, "value")
    
    SELECT * FROM c WHERE STRINGEQUALS(c.property, "value")
    
  • ORDER BY Lekérdezések:

    SELECT * FROM container c ORDER BY c.property
    
  • JOIN Lekérdezések:

    SELECT child FROM container c JOIN child IN c.properties WHERE child = 'value'
    

A tartományindexek skaláris értékeken (sztring vagy szám) használhatók. Az újonnan létrehozott tárolók alapértelmezett indexelési szabályzata minden sztring vagy szám esetében tartományindexeket kényszerít. A tartományindexek konfigurálásával kapcsolatos további információkért lásd: Tartományindexelési szabályzatok példái

Megjegyzés

Egy ORDER BY olyan záradék, amely egyetlen tulajdonság alapján rendel, mindig szükség van egy tartományindexre, és sikertelen lesz, ha a hivatkozott elérési út nem rendelkezik ilyenrel. Hasonlóképpen, egy ORDER BY lekérdezésnek, amely több tulajdonsággal rendel, mindig összetett indexre van szüksége.

Térbeli index

A térinformatikai indexek hatékony lekérdezéseket tesznek lehetővé térinformatikai objektumokon, például pontokon, vonalakon, sokszögeken és többpogonon. Ezek a lekérdezések ST_DISTANCE, ST_WITHIN ST_INTERSECTS kulcsszavakat használnak. Az alábbi példák térbeli indextípust használnak:

  • Térinformatikai távolságra vonatkozó lekérdezések:

    SELECT * FROM container c WHERE ST_DISTANCE(c.property, { "type": "Point", "coordinates": [0.0, 10.0] }) < 40
    
  • A lekérdezéseken belüli térinformatika:

    SELECT * FROM container c WHERE ST_WITHIN(c.property, {"type": "Point", "coordinates": [0.0, 10.0] })
    
  • Térinformatikai metszet-lekérdezések:

    SELECT * FROM c WHERE ST_INTERSECTS(c.property, { 'type':'Polygon', 'coordinates': [[ [31.8, -5], [32, -5], [31.8, -5] ]]  })  
    

A térbeli indexek megfelelően formázott GeoJSON-objektumokon használhatók. A pontok, vonalláncok, sokszögek és multipoligonok jelenleg támogatottak. A térbeli indexek konfigurálásának megismeréséhez lásd: Térbeli indexelési szabályzatok példái

Összetett indexek

Az összetett indexek növelik a hatékonyságot, ha több mezőn hajt végre műveleteket. Az összetett indextípus a következő célokra használható:

  • ORDER BY lekérdezések több tulajdonságon:

    SELECT * FROM container c ORDER BY c.property1, c.property2
    
  • Lekérdezések szűrővel és ORDER BY. Ezek a lekérdezések összetett indexet használhatnak, ha a szűrőtulajdonság hozzá van adva a ORDER BY záradékhoz.

    SELECT * FROM container c WHERE c.property1 = 'value' ORDER BY c.property1, c.property2
    
  • Két vagy több tulajdonság szűrőjével rendelkező lekérdezések, ahol legalább egy tulajdonság egyenlőségszűrő

    SELECT * FROM container c WHERE c.property1 = 'value' AND c.property2 > 'value'
    

Ha egy szűrő predikátum az egyik indextípust használja, a lekérdezési motor először kiértékeli, mielőtt beolvasja a többit. Ha például sql-lekérdezéssel rendelkezik, például SELECT * FROM c WHERE c.firstName = "Andrew" and CONTAINS(c.lastName, "Liu")

  • A fenti lekérdezés először azokat a bejegyzéseket szűri, ahol a firstName = "Andrew" az index használatával történik. Ezután átadja az összes firstName = "Andrew" bejegyzést egy későbbi folyamaton keresztül a CONTAINS szűrő predikátum kiértékeléséhez.

  • Felgyorsíthatja a lekérdezéseket, és elkerülheti a teljes tárolóvizsgálatokat, ha olyan függvényeket használ, amelyek teljes vizsgálatot végeznek, mint például a CONTAINS. További olyan szűrő-predikátumokat is hozzáadhat, amelyek az indexet használják a lekérdezések felgyorsításához. A szűrési záradékok sorrendje nem fontos. A lekérdezési motor kitalálja, hogy mely predikátumok szelektívebbek, és ennek megfelelően futtassa a lekérdezést.

Az összetett indexek konfigurálásának megismeréséhez lásd: Összetett indexelési szabályzatok példái

Indexhasználat

A lekérdezési motor ötféleképpen értékelheti ki a lekérdezési szűrőket, a leghatékonyabb és a legkevésbé hatékony szerint rendezve:

  • Indexkeresés
  • Pontos indexvizsgálat
  • Bővített indexvizsgálat
  • Teljes indexvizsgálat
  • Teljes vizsgálat

A tulajdonságútvonalak indexelésekor a lekérdezési motor a lehető leghatékonyabban használja az indexet. Az új tulajdonságútvonalak indexelése mellett semmit sem kell konfigurálnia az index használatának optimalizálásához. A lekérdezés kérelemegység-díja az indexhasználatból származó RU-díj és az elemek betöltéséből származó RU-díj kombinációja.

Az alábbi táblázat összefoglalja az indexek Azure Cosmos DB-ben való használatát:

Indexkeresés típusa Description Gyakori példák RU-díj az indexhasználatból A tranzakciós adattárból származó elemek betöltésének kérelemegység-díjai
Indexkeresés Csak a szükséges indexelt értékek olvasása, és csak az egyező elemek betöltése a tranzakciós adattárból Egyenlőségi szűrők, IN Egyenlőségi szűrőnkénti állandó Növekedés a lekérdezési eredményekben szereplő elemek száma alapján
Pontos indexvizsgálat Indexelt értékek bináris keresése és csak az egyező elemek betöltése a tranzakciós adattárból Tartomány-összehasonlítások (>, , <<= vagy >=), StartsWith Az indexkereséshez hasonlítható, az indexelt tulajdonságok számossága alapján enyhén nő Növekedés a lekérdezési eredményekben szereplő elemek száma alapján
Bővített indexvizsgálat Indexelt értékek optimalizált keresése (de kevésbé hatékony, mint bináris keresés), és csak a tranzakciós adattárból származó egyező elemek betöltése StartsWith (kis- és nagybetűk megkülönböztetése), StringEquals (kis- és nagybetűk megkülönböztetése) Enyhén nő az indexelt tulajdonságok számossága alapján Növekedés a lekérdezési eredményekben szereplő elemek száma alapján
Teljes indexvizsgálat Az indexelt értékek különböző készletének olvasása és csak az egyező elemek betöltése a tranzakciós adattárból Tartalmazza, EndsWith, RegexMatch, LIKE Lineáris növekedés az indexelt tulajdonságok számossága alapján Növekedés a lekérdezési eredményekben szereplő elemek száma alapján
Teljes vizsgálat Az összes elem betöltése a tranzakciós adattárból Felső, Alsó N/A Növekedés a tárolóban lévő elemek száma alapján

Lekérdezések írásakor olyan szűrő predikátumokat kell használnia, amelyek a lehető leghatékonyabban használják az indexet. Ha például vagy StartsWithContains működik a használati esetnél, érdemes választania StartsWith , mivel a teljes indexvizsgálat helyett pontos indexvizsgálatot végez.

Indexhasználat részletei

Ebben a szakaszban további részleteket ismertetünk arról, hogyan használják a lekérdezések az indexeket. Ez a részletességi szint nem szükséges az Azure Cosmos DB használatának megkezdéséhez, de a kíváncsi felhasználók számára részletesen dokumentálva van. A dokumentum korábbi részében megosztott példaelemre hivatkozunk:

Példaelemek:

{
  "id": 1,
  "locations": [
    { "country": "Germany", "city": "Berlin" },
    { "country": "France", "city": "Paris" }
  ],
  "headquarters": { "country": "Belgium", "employees": 250 },
  "exports": [
    { "city": "Moscow" },
    { "city": "Athens" }
  ]
}
{
  "id": 2,
  "locations": [
    { "country": "Ireland", "city": "Dublin" }
  ],
  "headquarters": { "country": "Belgium", "employees": 200 },
  "exports": [
    { "city": "Moscow" },
    { "city": "Athens" },
    { "city": "London" }
  ]
}

Az Azure Cosmos DB fordított indexet használ. Az index úgy működik, hogy az egyes JSON-elérési utakat az adott értéket tartalmazó elemek készletéhez társítja. Az elemazonosító-megfeleltetés a tároló számos különböző indexlapján jelenik meg. Íme egy mintadiagram egy tároló invertált indexéről, amely a két példaelemet tartalmazza:

Elérési út Érték Elemazonosítók listája
/locations/0/country Németország 1
/locations/0/country Írország 2
/locations/0/city Berlin 1
/locations/0/city Dublin 2
/locations/1/country Franciaország 1
/locations/1/city Párizs 1
/központ/ország Belgium 1, 2
/központ/alkalmazottak 200 2
/központ/alkalmazottak 250 1

Az invertált indexnek két fontos attribútuma van:

  • Egy adott elérési út esetében az értékek növekvő sorrendben vannak rendezve. Ezért a lekérdezési motor könnyen kiszolgálható ORDER BY az indexből.
  • Egy adott elérési út esetében a lekérdezési motor a lehetséges értékek különböző készletén keresztül vizsgálhatja át azokat az indexlapokat, ahol vannak eredmények.

A lekérdezési motor az invertált indexet négy különböző módon használhatja:

Indexkeresés

Tekintse meg a következő lekérdezést:

SELECT location
FROM location IN company.locations
WHERE location.country = 'France'`

A lekérdezési predikátum (olyan elemek szűrése, ahol bármely hely országa/régiója "Franciaország", megfelel az ábrán kiemelt útvonalnak:

Egy fa egy adott útvonalának megfelelő bejárási (keresési) diagram.

Mivel ez a lekérdezés egyenlőségszűrővel rendelkezik, a fa bejárása után gyorsan azonosíthatjuk a lekérdezés eredményeit tartalmazó indexlapokat. Ebben az esetben a lekérdezési motor felolvassa az 1. elemet tartalmazó indexoldalakat. Az indexkeresés a leghatékonyabb módszer az index használatára. Az indexkereséssel csak a szükséges indexoldalakat olvassuk be, és csak a lekérdezés eredményeiben szereplő elemeket töltjük be. Ezért az indexkeresési idő és az indexkeresés ru-díja hihetetlenül alacsony, függetlenül a teljes adatmennyiségtől.

Pontos indexvizsgálat

Tekintse meg a következő lekérdezést:

SELECT *
FROM company
WHERE company.headquarters.employees > 200

A lekérdezési predikátum (a több mint 200 alkalmazottat tartalmazó elemek szűrése) kiértékelhető az headquarters/employees elérési út pontos indexvizsgálatával. A pontos indexvizsgálat során a lekérdezési motor a lehetséges értékek különböző készletének bináris keresésével kezdi meg az elérési út értékének 200headquarters/employees helyét. Mivel az egyes elérési utak értékei növekvő sorrendben vannak rendezve, a lekérdezési motor könnyen elvégezhet bináris keresést. Miután a lekérdezési motor megtalálta az értéket 200, elkezdi beolvasni az összes többi indexlapot (növekvő irányba haladva).

Mivel a lekérdezési motor bináris keresést végezhet a felesleges indexlapok beolvasásának elkerülése érdekében, a pontos indexvizsgálatok általában hasonló késéssel és ru-díjakkal rendelkeznek az indexkeresési műveletekhez.

Bővített indexvizsgálat

Tekintse meg a következő lekérdezést:

SELECT *
FROM company
WHERE STARTSWITH(company.headquarters.country, "United", true)

A lekérdezési predikátum (a "United" kis- és nagybetűkkel kezdődő helyen található központi elemek szűrése) kiértékelhető az headquarters/country elérési út kibővített indexvizsgálatával. A kibővített indexvizsgálatot végező műveletek optimalizálása segít elkerülni, hogy minden indexoldalt beolvassunk, de valamivel drágábbak, mint egy pontos indexvizsgálat bináris keresése.

A kis- és nagybetűk megkülönböztetésének kiértékelésekor például a lekérdezési StartsWithmotor ellenőrzi az indexet a kis- és nagybetűk különböző lehetséges kombinációinál. Ez az optimalizálás lehetővé teszi a lekérdezési motor számára, hogy elkerülje a legtöbb indexlap olvasását. A különböző rendszerfüggvények különböző optimalizálásokkal rendelkeznek, amelyekkel elkerülhetik az indexlapok olvasását, így széles körben bővített indexvizsgálatként vannak kategorizálva.

Teljes indexvizsgálat

Tekintse meg a következő lekérdezést:

SELECT *
FROM company
WHERE CONTAINS(company.headquarters.country, "United")

A lekérdezési predikátum (a "United" elemet tartalmazó helyen található központtal rendelkező elemek szűrése headquarters/country ) az elérési út indexvizsgálatával értékelhető ki. A pontos indexvizsgálattól eltérően a teljes indexvizsgálat mindig a lehetséges értékek különböző készletén halad végig, hogy azonosítsa azokat az indexlapokat, ahol vannak eredmények. Ebben az esetben Contains a rendszer az indexen fut. Az indexkeresési idő és a kérelemegység-díj az indexvizsgálatok esetében az elérési út számosságának növekedésével nő. Más szóval minél több különböző értéket kell megvizsgálnia a lekérdezési motornak, annál nagyobb a késés és a kérelemegység-terhelés a teljes indexvizsgálatban.

Vegyük például két tulajdonságot: town és country. A város számossága 5000, a számossága country pedig 200. Íme két példa lekérdezés, amelyek mindegyike tartalmaz egy Olyan rendszerfüggvényt, amely teljes indexvizsgálatot végez a town tulajdonságon. Az első lekérdezés több kérelemegységet használ, mint a második lekérdezés, mert a város számossága magasabb, mint country.

SELECT *
FROM c
WHERE CONTAINS(c.town, "Red", false)
SELECT *
FROM c
WHERE CONTAINS(c.country, "States", false)

Teljes vizsgálat

Bizonyos esetekben előfordulhat, hogy a lekérdezési motor nem tudja kiértékelni a lekérdezésszűrőt az index használatával. Ebben az esetben a lekérdezési motornak be kell töltenie a tranzakciós tároló összes elemét a lekérdezésszűrő kiértékeléséhez. A teljes vizsgálat nem használja az indexet, és a teljes adatmérettel lineárisan növekvő ru-díjjal rendelkezik. Szerencsére a teljes vizsgálatot igénylő műveletek ritkák.

Összetett szűrőkifejezéseket tartalmazó lekérdezések

A korábbi példákban csak azokat a lekérdezéseket vettük figyelembe, amelyek egyszerű szűrőkifejezésekkel rendelkeztek (például egyetlen egyenlőség- vagy tartományszűrővel rendelkező lekérdezések). A valóságban a legtöbb lekérdezés sokkal összetettebb szűrőkifejezésekkel rendelkezik.

Tekintse meg a következő lekérdezést:

SELECT *
FROM company
WHERE company.headquarters.employees = 200 AND CONTAINS(company.headquarters.country, "United")

A lekérdezés végrehajtásához a lekérdezési motornak indexkeresést kell végeznie headquarters/employees , és teljes indexvizsgálatot kell végeznie a következőn: headquarters/country. A lekérdezési motor belső heurisztikus elemekkel rendelkezik, amelyeket a lekérdezésszűrő kifejezés lehető leghatékonyabb kiértékeléséhez használ. Ebben az esetben a lekérdezési motornak nem kell elolvasnia a felesleges indexlapokat az indexkeresés első lépésével. Ha például csak 50 elem felel meg az egyenlőségi szűrőnek, a lekérdezési motornak csak az 50 elemet tartalmazó indexlapokon kell kiértékelnie Contains . A teljes tároló indexvizsgálatára nincs szükség.

Skaláris összesítő függvények indexkihasználtsága

Az összesítő függvényekkel rendelkező lekérdezések kizárólag az indexre támaszkodhatnak a használatukhoz.

Bizonyos esetekben az index hamis pozitív értékeket adhat vissza. Az index kiértékelésekor Contains például az indexben lévő egyezések száma meghaladhatja a lekérdezési eredmények számát. A lekérdezési motor betölti az összes index egyezést, kiértékeli a szűrőt a betöltött elemeken, és csak a megfelelő eredményeket adja vissza.

A legtöbb lekérdezés esetében a hamis pozitív index-egyezések betöltése nem befolyásolja az index kihasználtságát.

Lásd példaként az alábbi lekérdezést:

SELECT *
FROM company
WHERE CONTAINS(company.headquarters.country, "United")

A Contains rendszerfüggvény téves pozitív találatokat adhat vissza, ezért a lekérdezési motornak ellenőriznie kell, hogy minden betöltött elem megfelel-e a szűrőkifejezésnek. Ebben a példában előfordulhat, hogy a lekérdezési motornak csak néhány további elemet kell betöltenie, így az index kihasználtságára és a kérelemegység-terhelésre gyakorolt hatás minimális.

Az aggregátumfüggvényekkel rendelkező lekérdezések azonban kizárólag az indexre támaszkodhatnak a használatukhoz. Vegyük például a következő lekérdezést összesítéssel Count :

SELECT COUNT(1)
FROM company
WHERE CONTAINS(company.headquarters.country, "United")

Az első példához hasonlóan a Contains rendszerfüggvény is visszaadhat néhány hamis pozitív egyezést. SELECT * A lekérdezéstől eltérően azonban a Count lekérdezés nem tudja kiértékelni a betöltött elemek szűrőkifejezését az összes index egyezésének ellenőrzéséhez. A Count lekérdezésnek kizárólag az indexre kell támaszkodnia, így ha van rá esély, hogy egy szűrőkifejezés hamis pozitív találatokat ad vissza, a lekérdezési motor teljes vizsgálatot végez.

Az alábbi összesítő függvényekkel rendelkező lekérdezések kizárólag az indexre támaszkodhatnak, ezért egyes rendszerfüggvények kiértékeléséhez teljes vizsgálatra van szükség.

Következő lépések

Az indexelésről az alábbi cikkekben olvashat bővebben: