Indextabel-patroon

Azure Storage

Indexen maken van de velden in gegevensarchieven waarnaar vaak wordt verwezen door query's. Dit patroon kan de queryprestaties verbeteren doordat toepassingen sneller de gegevens kunnen vinden die ze moeten ophalen uit een gegevensarchief.

Context en probleem

Veel gegevensarchieven maken gebruik van een primaire sleutel om de gegevens voor een verzameling entiteiten te ordenen. Een toepassing kan deze sleutel gebruiken om gegevens te zoeken en op te halen. In de afbeelding ziet u een voorbeeld van een gegevensarchief met klantgegevens. De primaire sleutel is de klant-id. In de afbeelding ziet u klantgegevens die zijn geordend op de primaire sleutel (Customer ID).

Afbeelding 1 - Klantgegevens geordend op de primaire sleutel (Customer ID)

Hoewel de primaire sleutel handig is voor query's die gegevens ophalen die zijn gebaseerd op de waarde van deze sleutel, is de primaire sleutel mogelijk onbruikbaar voor een toepassing als deze gegevens moet ophalen die zijn gebaseerd op een ander veld. In het bovenstaande voorbeeld kan een toepassing de primaire sleutel Customer ID niet gebruiken voor het ophalen van klanten als in de query uitsluitend wordt verwezen naar de waarde van een ander kenmerk, zoals de plaats waarin de klant is gevestigd. Om een dergelijke query uit te voeren, moet de toepassing mogelijk elke klantrecord ophalen en onderzoeken, wat erg tijdrovend kan zijn.

Veel relationele databasebeheersystemen ondersteunen secundaire indexen. Een secundaire index is een afzonderlijke gegevensstructuur die is geordend op een of meer niet-primaire (secundaire) sleutelvelden. Deze index geeft aan waar de gegevens voor elke geïndexeerde waarde zijn opgeslagen. De items in een secundaire index worden meestal gesorteerd op de waarde van de secundaire sleutels om het snel opzoeken van gegevens mogelijk te maken. Deze indexen worden doorgaans automatisch onderhouden door het databasebeheersysteem.

U kunt zoveel secundaire indexen maken als u nodig hebt voor het ondersteunen van de verschillende query's die de toepassing uitvoert. Stel dat u een klantentabel hebt in een relationele database waarin de klant-id de primaire sleutel is. Als in de toepassing klanten vaak worden opgezocht op de plaats waarin ze zijn gevestigd, is het zinvol om een secundaire index toe te voegen voor het veld Plaats.

Hoewel secundaire indexen gebruikelijk zijn in relationele systemen, bieden sommige NoSQL-gegevensarchieven die worden gebruikt door cloudtoepassingen geen equivalente functie.

Oplossing

Als het gegevensarchief geen ondersteuning biedt voor secundaire indexen, kunt u deze handmatig emuleren door uw eigen indextabellen te maken. In een indextabel worden de gegevens geordend op een opgegeven sleutel. Er worden over het algemeen drie strategieën gebruikt voor het structureren van een indextabel, afhankelijk van het aantal secundaire indexen die vereist zijn en de aard van de query's die een toepassing uitvoert.

De eerste strategie bestaat uit het dupliceren van de gegevens in elke indextabel, en deze vervolgens op andere sleutels te ordenen (volledige denormalisatie). In de volgende afbeelding ziet u indextabellen waarin dezelfde klantgegevens nu zijn geordend op Town en LastName.

Afbeelding 2 - Gegevens gedupliceerd in elke indextabel

Deze strategie is geschikt als de gegevens relatief statisch zijn in vergelijking met het aantal keren dat de gegevens worden opgevraagd met behulp van elke sleutel. Als de gegevens dynamischer zijn, wordt de verwerkingsoverhead voor het onderhouden van elke indextabel te groot om deze benadering nog effectief te laten zijn. Bovendien gaat de hoeveelheid vereiste schijfruimte voor het opslaan van de dubbele gegevens een rol spelen als de hoeveelheid gegevens erg groot is.

De tweede strategie bestaat uit het maken van genormaliseerde indextabellen die zijn geordend op verschillende sleutels en die verwijzen naar de oorspronkelijke gegevens met behulp van de primaire sleutel in plaats van de gegevens te dupliceren, zoals u kunt zien in de volgende afbeelding. De oorspronkelijke gegevens staan in een zogenaamde feitentabel (Fact Table).

Afbeelding 3 - In elke indextabel wordt verwezen naar de gegevens

Deze techniek bespaart ruimte en vermindert de overhead die gepaard gaat met het onderhouden van dubbele gegevens. Het nadeel is dat een toepassing twee opzoekbewerkingen moet uitvoeren om gegevens te vinden met behulp van een secundaire sleutel: eerst moet de primaire sleutel voor de gegevens worden gezocht in de indextabel en daarna moet deze primaire sleutel worden gebruikt om de gegevens te zoeken in de feitentabel.

De derde strategie bestaat uit het maken van gedeeltelijk genormaliseerde indextabellen die zijn geordend op verschillende sleutels die vaak opgehaalde velden dupliceren. U kunt dan verwijzen naar de feitentabel om toegang te krijgen tot velden die minder vaak worden geraadpleegd. In de volgende afbeelding ziet u hoe vaak gebruikte gegevens in elke indextabel zijn gedupliceerd.

Afbeelding 4 - Veelgebruikte gegevens zijn gedupliceerd in elke indextabel

Met deze strategie kiest u voor een compromis tussen de eerste twee methoden. De gegevens voor algemene query's kunnen snel worden opgehaald via één opzoekbewerking, terwijl de benodigde ruimte en overhead voor onderhoud niet zo ingrijpend zijn als bij duplicatie van de volledige gegevensset.

Als een toepassing regelmatig query's uitvoert op gegevens door een combinatie van waarden op te geven (bijvoorbeeld 'Zoek alle klanten die in Redmond wonen en die een achternaam van Smith hebben'), kunt u de sleutels voor de items in de indextabel implementeren als een samenvoeging van het kenmerk Town en het kenmerk LastName. In de volgende afbeelding ziet u een indextabel die is gebaseerd op samengestelde sleutels. De sleutels worden eerst gesorteerd op Town, en vervolgens op LastName voor records met dezelfde waarde voor Town.

Afbeelding 5 - Een indextabel die is gebaseerd op samengestelde sleutels

Indextabellen kunnen de prestaties verbeteren van querybewerkingen op gegevens die zijn verdeeld over shards, en zijn met name nuttig wanneer er een hash-code wordt toegepast op de shard-sleutel. In de volgende afbeelding ziet u een voorbeeld waarin de shard-sleutel een hash is van de klant-id (Customer ID). De indextabel kan gegevens ordenen op de waarde zonder hash-code (Town en LastName), en de shard-sleutel met hash-code doorgeven als de opzoekgegevens. Hierdoor hoeft de toepassing niet steeds opnieuw hash-sleutels te berekenen (een intensieve bewerking) als er gegevens moeten worden opgehaald die binnen een bereik vallen of gegevens die moeten worden opgehaald in de volgorde van de sleutel zonder hash-code. Een query zoals 'Alle klanten zoeken die in Redmond wonen' kan bijvoorbeeld snel worden opgelost door de overeenkomende items in de indextabel te zoeken, waar ze allemaal zijn opgeslagen in een aaneengesloten blok. Vervolgens kunnen de verwijzingen naar de klantgegevens worden gevolgd met behulp van de shard-sleutels die zijn opgeslagen in de indextabel.

Afbeelding 6: Een indextabel voor het snel opzoeken van gegevens in shards

Problemen en overwegingen

Beschouw de volgende punten als u besluit hoe u dit patroon wilt implementeren:

  • De overhead van het onderhouden van secundaire indexen kan aanzienlijk zijn. Het is daarom belangrijk dat u de query's analyseert en begrijpt die door uw toepassing worden gebruikt. Maak alleen indextabellen wanneer de kans groot is dat deze regelmatig worden gebruikt. Maak geen speculatieve indextabellen ter ondersteuning van query's die niet of slechts sporadisch worden uitgevoerd door een toepassing.

  • Het dupliceren van gegevens in een indextabel kan aanzienlijke overhead toevoegen voor wat betreft opslagkosten en het werk dat nodig is om meerdere kopieën van gegevens te onderhouden.

  • Het implementeren van een indextabel als een genormaliseerde structuur die verwijst naar de oorspronkelijke gegevens, betekent dat een toepassing twee opzoekbewerkingen moet uitvoeren om gegevens te vinden. Met de eerste bewerking wordt de indextabel doorzocht om de primaire sleutel op te halen, terwijl de tweede bewerking nodig is om met behulp van de primaire sleutel de gewenste gegevens op te halen.

  • Als een systeem een aantal indextabellen bevat voor zeer grote gegevenssets, kan het lastig zijn om consistentie te garanderen tussen de indextabellen en de oorspronkelijke gegevens. Het is in dat geval misschien mogelijk om de toepassing te ontwerpen rond het model van uiteindelijke consistentie. Als een toepassing bijvoorbeeld gegevens moet invoegen, bijwerken of verwijderen, kan dit door een bericht in een wachtrij te plaatsen en een afzonderlijke taak de bewerking te laten uitvoeren en de indextabellen te laten onderhouden die asynchroon verwijzen naar deze gegevens. Zie Inleiding over gegevensconsistentie voor meer informatie over het implementeren van uiteindelijke consistentie.

    Tip

    Opslagtabellen van Microsoft Azure bieden ondersteuning voor transactionele updates voor wijzigingen van gegevens die in dezelfde partitie zijn opgeslagen (aangeduid als groepstransacties voor entiteiten). Als u de gegevens voor een feitentabel en een of meer indextabellen in dezelfde partitie kunt opslaan, kunt u deze functie gebruiken om consistentie te garanderen.

  • Indextabellen kunnen zelf zijn gepartitioneerd of zijn verdeeld in shards.

Wanneer dit patroon gebruiken

Gebruik dit patroon om de queryprestaties te verbeteren wanneer een toepassing vaak gegevens moet ophalen met behulp van een andere sleutel dan de primaire sleutel (of shard-sleutel).

In de volgende gevallen is dit patroon mogelijk niet geschikt:

  • De gegevens zijn vluchtig. Een indextabel kan zeer snel verouderd raken, waardoor deze inefficiënt wordt of de overhead van het onderhouden van de tabel niet meer opweegt tegen de voordelen van een indextabel.
  • Een veld dat is geselecteerd als de secundaire sleutel voor een indextabel is niet-onderscheidend en kan slechts een kleine set waarden hebben (bijvoorbeeld geslacht).
  • Het percentage gegevenswaarden voor een veld dat is geselecteerd als de secundaire sleutel voor een indextabel loopt sterk uiteen. Als bijvoorbeeld 90% van de records dezelfde waarde bevat in een veld, is de kans groot dat het maken en onderhouden van een indextabel voor het opzoeken van gegevens die zijn gebaseerd op dit veld, meer overhead vereist dan het sequentieel scannen van de gegevens. Als query's echter heel vaak gericht zijn op waarden die in de resterende 10% liggen, kan deze index nuttig zijn. Het is dan ook belangrijk dat u begrijpt welke query's uw toepassing uitvoert en hoe vaak deze worden uitgevoerd.

Workloadontwerp

Een architect moet evalueren hoe het indextabelpatroon kan worden gebruikt in het ontwerp van hun workload om de doelstellingen en principes te verhelpen die worden behandeld in de pijlers van het Azure Well-Architected Framework. Voorbeeld:

Pijler Hoe dit patroon ondersteuning biedt voor pijlerdoelen
Beslissingen over betrouwbaarheidsontwerp helpen uw workload bestand te worden tegen storingen en ervoor te zorgen dat deze herstelt naar een volledig functionerende status nadat er een fout is opgetreden. Omdat clients via een opzoekproces naar hun shard, partitie of eindpunt worden verwezen, kunt u dit patroon gebruiken om een failoverbenadering voor gegevenstoegang te vergemakkelijken.

- RE:06 Gegevenspartitionering
- RE:09 Herstel na noodgevallen
Prestatie-efficiëntie helpt uw workload efficiënt te voldoen aan de vereisten door optimalisaties in schalen, gegevens, code. Clients worden verwezen naar hun shard, partitie of eindpunt, waardoor dynamische gegevenspartitionering voor prestatieoptimalisatie mogelijk is.

- PE:05 Schalen en partitioneren
- PE:08 Gegevensprestaties

Net als bij elke ontwerpbeslissing moet u rekening houden met eventuele compromissen ten opzichte van de doelstellingen van de andere pijlers die met dit patroon kunnen worden geïntroduceerd.

Opmerking

Azure-opslagtabellen vormen een zeer schaalbaar gegevensarchief van sleutel/waardeparen voor toepassingen die in de cloud worden uitgevoerd. Gegevenswaarden worden opgeslagen en opgehaald door toepassingen door het opgeven van een sleutel. De gegevenswaarden kunnen meerdere velden bevatten, maar de structuur van een gegevensitem is niet relevant voor tabelopslag. Een gegevensitem wordt namelijk altijd als een matrix van bytes verwerkt.

Azure-opslagtabellen bieden ook ondersteunen voor sharding. De sharding-sleutel bevat twee elementen, een partitiesleutel en een rijsleutel. Items met dezelfde partitiesleutel worden in dezelfde partitie (shard) opgeslagen. Binnen een shard worden de items opgeslagen in de volgorde van de rijsleutel. Tabelopslag is geoptimaliseerd voor het uitvoeren van query's die gegevens ophalen die binnen een aaneengesloten bereik van rijsleutelwaarden binnen een partitie vallen. Als u cloudtoepassingen bouwt die gegevens opslaan in Azure-tabellen, moet u hiermee rekening houden als u de gegevens gaat structureren.

Laten we dit eens bekijken aan de hand van een toepassing die informatie over films opslaat. In de toepassing worden regelmatig films opgevraagd op genre (actie, documentaire, historisch, comedy, drama, enzovoort). U kunt een Azure-tabel maken met partities voor elk genre door het genre als de partitiesleutel te gebruiken en de naam van de film op te geven als de rijsleutel, zoals u kunt zien in de volgende afbeelding.

Afbeelding 7: Filmgegevens opgeslagen in een Azure-tabel

Deze aanpak is minder effectief als de toepassing ook films moet vinden op hoofdrolspeler (Starring Actor). In dit geval kunt u een afzonderlijke Azure-tabel maken die als indextabel fungeert. De partitiesleutel is de acteur en de rijsleutel is de naam van de film. De gegevens voor elke acteur worden opgeslagen in afzonderlijke partities. Als een film meer dan één hoofdrolspeler heeft, wordt dezelfde film in meerdere partities opgeslagen.

U kunt de filmgegevens in de waarden in elke partitie dupliceren door de eerste benadering te hanteren die wordt beschreven in de bovenstaande sectie Oplossing. De kans is echter groot dat elke film meerdere keren wordt gerepliceerd (één keer voor elke acteur), zodat het waarschijnlijk efficiënter is om de gegevens gedeeltelijk te denormaliseren voor ondersteuning van de meest voorkomende query's (zoals de namen van de andere acteurs) en de toepassing in staat te stellen alle overige gegevens op te halen door het toevoegen van de partitiesleutel die nodig is voor het vinden van de volledige gegevens in de genre-partities. Deze benadering wordt beschreven door de derde optie in de sectie Oplossing. U ziet deze benadering ook in de volgende afbeelding.

Afbeelding 8 - Acteur-partities die fungeren als indextabellen voor filmgegevens

Volgende stappen

  • Inleiding over gegevensconsistentie. Een indextabel moet worden onderhouden wanneer de geïndexeerde gegevens veranderen. Het is mogelijk dat het praktisch niet haalbaar is of niet wenselijk is om in de cloud bewerkingen uit te voeren waarbij dezelfde transactie wordt gebruikt om een index bij te werken en de gegevens te wijzigen. In dat geval is een benadering gericht op uiteindelijke consistentie beter geschikt. Bevat informatie over de problemen betreffende uiteindelijke consistentie.

De volgende patronen zijn mogelijk ook relevant bij het implementeren van dit patroon:

  • Sharding-patroon. Het patroon Indextabel wordt vaak gebruikt in combinatie met gegevens die zijn gepartitioneerd met behulp van shards. U vindt hier meer informatie over het onderverdelen van een gegevensarchief in een set met shards.
  • Gerealiseerde weergave-patroon. In plaats van gegevens te indexeren om ondersteuning te bieden voor query's waarin gegevens worden samengevat, kan het efficiënter zijn om een gerealiseerde weergave van de gegevens te maken. U leest hier hoe u ondersteuning biedt voor efficiënte samenvattingsquery's door vooraf ingevulde weergaven van gegevens te genereren.