Způsoby návrhu tabulek

Tento článek popisuje některé vzory vhodné pro použití s řešeními Table Service. Také se dozvíte, jak můžete prakticky řešit některé problémy a kompromisy, které jsou popsány v jiných článcích o návrhu služby Table Storage. Následující diagram shrnuje vztahy mezi různými vzory:

to look up related data

Výše uvedená mapa vzorů zvýrazňuje některé vztahy mezi vzory (modrými) a vzory (oranžovými), které jsou popsané v tomto průvodci. Existuje mnoho dalších vzorů, které stojí za zvážení. Jedním z klíčových scénářů služby Table Service je například použití materializovaného vzoru zobrazení ze vzoru CQRS (Command Query Responsibility Segregation).

Model sekundárního indexu uvnitř oddílu

Uložte několik kopií každé entity pomocí různých hodnot RowKey (ve stejném oddílu), abyste umožnili rychlé a efektivní vyhledávání a alternativní pořadí řazení pomocí různých hodnot RowKey . Aktualizace mezi kopiemi lze udržovat konzistentní pomocí transakcí skupin entit (EGT).

Kontext a problém

Služba Table service automaticky indexuje entity pomocí hodnot PartitionKey a RowKey . Díky tomu může klientská aplikace efektivně načíst entitu pomocí těchto hodnot. Například pomocí struktury tabulky uvedené níže může klientská aplikace pomocí dotazu typu point načíst jednotlivou entitu zaměstnance pomocí názvu oddělení a ID zaměstnance ( hodnoty PartitionKey a RowKey ). Klient může také načíst entity seřazené podle ID zaměstnance v rámci každého oddělení.

Graphic of employee entity where a client application can use a point query to retrieve an individual employee entity by using the department name and the employee ID (the PartitionKey and RowKey values).

Pokud chcete mít také možnost najít entitu zaměstnance na základě hodnoty jiné vlastnosti, například e-mailové adresy, musíte k vyhledání shody použít méně efektivní kontrolu oddílů. Důvodem je to, že služba Table Service neposkytuje sekundární indexy. Kromě toho není možné požádat o seznam zaměstnanců seřazený v jiném pořadí než pořadí RowKey .

Řešení

Chcete-li obejít nedostatek sekundárních indexů, můžete uložit více kopií každé entity s každou kopií pomocí jiné hodnoty RowKey . Pokud uložíte entitu se strukturami zobrazenými níže, můžete efektivně načíst entity zaměstnanců na základě e-mailové adresy nebo ID zaměstnance. Hodnoty předpony pro RowKey, "empid_" a "email_" umožňují dotazovat se na jednoho zaměstnance nebo rozsah zaměstnanců pomocí rozsahu e-mailových adres nebo ID zaměstnanců.

Graphic showing employee entity with varying RowKey values

Následující dvě kritéria filtru (jedno vyhledávání podle ID zaměstnance a jedno vyhledávání podle e-mailové adresy) oba určují dotazy na body:

  • $filter=(PartitionKey eq 'Sales') a (RowKey eq 'empid_000223')
  • $filter=(PartitionKey eq 'Sales') a (RowKey eq 'email_jonesj@contoso.com')

Pokud se dotazujete na rozsah entit zaměstnanců, můžete zadat rozsah seřazený v pořadí ID zaměstnance nebo rozsah seřazený v pořadí e-mailových adres dotazováním entit s příslušnou předponou v klíči řádku.

  • Pokud chcete najít všechny zaměstnance v prodejním oddělení s ID zaměstnance v rozsahu 000100 až 000199 použít: $filter=(PartitionKey eq 'Sales') a (RowKey ge 'empid_000100') a (RowKey le 'empid_000199')

  • Pokud chcete najít všechny zaměstnance v prodejním oddělení s e-mailovou adresou začínající písmenem "a", použijte: $filter=(PartitionKey eq 'Sales') a (RowKey ge 'email_a') a (RowKey lt 'email_b')

    Syntaxe filtru použitá v příkladech výše je z rozhraní REST API služby Table Service. Další informace najdete v tématu Entity dotazu.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Úložiště Table Storage je poměrně levné, takže náklady na ukládání duplicitních dat by neměly být zásadním problémem. Vždy byste ale měli vyhodnotit náklady na návrh na základě očekávaných požadavků na úložiště a přidat duplicitní entity, které budou podporovat dotazy, které vaše klientská aplikace spustí.

  • Protože sekundární entity indexu jsou uloženy ve stejném oddílu jako původní entity, měli byste zajistit, abyste nepřekročili cíle škálovatelnosti pro jednotlivé oddíly.

  • Duplicitní entity můžete udržovat v souladu s ostatními pomocí EGT a aktualizovat dvě kopie entity atomicky. To znamená, že byste měli uložit všechny kopie entity ve stejném oddílu. Další informace najdete v části Použití transakcí skupiny entit.

  • Hodnota použitá pro RowKey musí být pro každou entitu jedinečná. Zvažte použití složených hodnot klíče.

  • Odsazení číselných hodnot v RowKey (například ID zaměstnance 000223) umožňuje správné řazení a filtrování na základě horních a dolních hranic.

  • Nemusíte nutně duplikovat všechny vlastnosti entity. Pokud například dotazy, které vyhledávají entity pomocí e-mailové adresy v RowKey , nikdy nepotřebují věk zaměstnance, mohou mít tyto entity následující strukturu:

    Graphic of employee entity

  • Obvykle je lepší ukládat duplicitní data a zajistit, abyste mohli načíst všechna potřebná data pomocí jednoho dotazu, než použít jeden dotaz k vyhledání entity a jiné k vyhledání požadovaných dat.

Kdy se má tento model použít

Tento vzor použijte, když klientská aplikace potřebuje načíst entity pomocí různých klíčů, když klient potřebuje načíst entity v různých pořadích řazení a kde můžete identifikovat každou entitu pomocí různých jedinečných hodnot. Při vyhledávání entit pomocí různých hodnot RowKey byste ale měli být jisti, že nepřekračujete limity škálovatelnosti oddílů.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Model sekundárního indexu mezi oddíly

Uložte několik kopií každé entity pomocí různých hodnot RowKey v samostatných oddílech nebo v samostatných tabulkách, abyste umožnili rychlé a efektivní vyhledávání a alternativní pořadí řazení pomocí různých hodnot RowKey.

Kontext a problém

Služba Table service automaticky indexuje entity pomocí hodnot PartitionKey a RowKey . Díky tomu může klientská aplikace efektivně načíst entitu pomocí těchto hodnot. Například pomocí struktury tabulky uvedené níže může klientská aplikace pomocí dotazu typu point načíst jednotlivou entitu zaměstnance pomocí názvu oddělení a ID zaměstnance ( hodnoty PartitionKey a RowKey ). Klient může také načíst entity seřazené podle ID zaměstnance v rámci každého oddělení.

Graphic of employee entity structure that, when used, a client application can use a point query to retrieve an individual employee entity by using the department name and the employee ID (the PartitionKey and RowKey values).

Pokud chcete mít také možnost najít entitu zaměstnance na základě hodnoty jiné vlastnosti, například e-mailové adresy, musíte k vyhledání shody použít méně efektivní kontrolu oddílů. Důvodem je to, že služba Table Service neposkytuje sekundární indexy. Kromě toho není možné požádat o seznam zaměstnanců seřazený v jiném pořadí než pořadí RowKey .

Očekáváte velký objem transakcí vůči těmto entitám a chcete minimalizovat riziko omezování služby Table Service.

Řešení

Chcete-li obejít nedostatek sekundárních indexů, můžete uložit více kopií každé entity s každou kopií pomocí různých hodnot PartitionKey a RowKey . Pokud uložíte entitu se strukturami zobrazenými níže, můžete efektivně načíst entity zaměstnanců na základě e-mailové adresy nebo ID zaměstnance. Hodnoty předpony pro PartitionKey, "empid_" a "email_" umožňují určit, který index chcete použít pro dotaz.

Graphic showing employee entity with primary index and employee entity with secondary index

Následující dvě kritéria filtru (jedno vyhledávání podle ID zaměstnance a jedno vyhledávání podle e-mailové adresy) oba určují dotazy na body:

  • $filter=(PartitionKey eq 'empid_Sales') a (RowKey eq '000223')
  • $filter=(PartitionKey eq 'email_Sales') a (RowKey eq 'jonesj@contoso.com')

Pokud se dotazujete na rozsah entit zaměstnanců, můžete zadat rozsah seřazený v pořadí ID zaměstnance nebo rozsah seřazený v pořadí e-mailových adres dotazováním entit s příslušnou předponou v klíči řádku.

  • Pokud chcete najít všechny zaměstnance v prodejním oddělení s ID zaměstnance v rozsahu 000100000199 seřazené v objednávce ID zaměstnance, použijte: $filter=(PartitionKey eq 'empid_Sales') a (RowKey ge '000100') a (RowKey le '000199')
  • Pokud chcete najít všechny zaměstnance v prodejním oddělení s e-mailovou adresou, která začíná na "a" seřazené v objednávce e-mailových adres, použijte: $filter=(PartitionKey eq 'email_Sales') a (RowKey ge 'a') a (RowKey lt 'b').

Syntaxe filtru použitá v příkladech výše je z rozhraní REST API služby Table Service. Další informace najdete v tématu Entity dotazu.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Duplicitní entity můžete zachovat tak, že se vzájemně konzistentně konzistentně zachovají pomocí vzoru transakcí s konzistencí typu Nakonec konzistentní, aby se zachovaly primární a sekundární entity indexu.

  • Úložiště Table Storage je poměrně levné, takže náklady na ukládání duplicitních dat by neměly být zásadním problémem. Vždy byste ale měli vyhodnotit náklady na návrh na základě očekávaných požadavků na úložiště a přidat duplicitní entity, které budou podporovat dotazy, které vaše klientská aplikace spustí.

  • Hodnota použitá pro RowKey musí být pro každou entitu jedinečná. Zvažte použití složených hodnot klíče.

  • Odsazení číselných hodnot v RowKey (například ID zaměstnance 000223) umožňuje správné řazení a filtrování na základě horních a dolních hranic.

  • Nemusíte nutně duplikovat všechny vlastnosti entity. Pokud například dotazy, které vyhledávají entity pomocí e-mailové adresy v RowKey , nikdy nepotřebují věk zaměstnance, mohou mít tyto entity následující strukturu:

    Graphic showing employee entity with secondary index

  • Obvykle je lepší ukládat duplicitní data a zajistit, abyste mohli načíst všechna potřebná data pomocí jednoho dotazu, než použít jeden dotaz k vyhledání entity pomocí sekundárního indexu a jiného k vyhledání požadovaných dat v primárním indexu.

Kdy se má tento model použít

Tento vzor použijte, když klientská aplikace potřebuje načíst entity pomocí různých klíčů, když klient potřebuje načíst entity v různých pořadích řazení a kde můžete identifikovat každou entitu pomocí různých jedinečných hodnot. Tento vzor použijte, pokud se chcete vyhnout překročení limitů škálovatelnosti oddílů při vyhledávání entit pomocí různých hodnot RowKey .

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Model nakonec konzistentních transakcí

Povolte nakonec konzistentní chování napříč hranicemi oddílů nebo hranicemi systému úložiště pomocí front Azure.

Kontext a problém

EgT umožňují atomické transakce napříč více entitami, které sdílejí stejný klíč oddílu. Z důvodů výkonu a škálovatelnosti se můžete rozhodnout ukládat entity, které mají požadavky na konzistenci v samostatných oddílech nebo v samostatném systému úložiště: v takovém scénáři nemůžete k zachování konzistence použít egT. Můžete mít například požadavek na zachování konečné konzistence mezi:

  • Entity uložené ve dvou různých oddílech ve stejné tabulce, v různých tabulkách nebo v různých účtech úložiště.
  • Entita uložená ve službě Table Service a objekt blob uložený ve službě Blob.
  • Entita uložená ve službě Table Service a soubor v systému souborů.
  • Entita uložená ve službě Table Service je ještě indexovaná pomocí služby Azure Cognitive Search.

Řešení

Pomocí front Azure můžete implementovat řešení, které zajišťuje konečnou konzistenci ve dvou nebo více oddílech nebo systémech úložiště. Pokud chcete tento přístup znázornit, předpokládejme, že potřebujete mít možnost archivovat staré entity zaměstnanců. Staré entity zaměstnanců jsou zřídka dotazovány a měly by být vyloučeny z aktivit, které se zabývají aktuálními zaměstnanci. Chcete-li tento požadavek implementovat, uložíte aktivní zaměstnance do aktuální tabulky a starých zaměstnanců v tabulce Archiv . Archivace zaměstnance vyžaduje, abyste entitu odstranili z aktuální tabulky a přidali ji do tabulky Archiv , ale k provedení těchto dvou operací nemůžete použít EGT. Aby se zabránilo riziku, že selhání způsobí, že se entita objeví v obou tabulkách nebo v žádné tabulce, musí být operace archivace nakonec konzistentní. Následující sekvenční diagram popisuje kroky v této operaci. Další podrobnosti jsou uvedeny pro cesty výjimek v následujícím textu.

Solution diagram for eventual consistency

Klient zahájí operaci archivace umístěním zprávy do fronty Azure v tomto příkladu pro archivaci zaměstnance č. 456. Role pracovního procesu se dotazuje fronty na nové zprávy; když ji najde, přečte zprávu a ponechá skrytou kopii ve frontě. Role pracovního procesu dále načte kopii entity z aktuální tabulky, vloží kopii do tabulky Archiv a potom odstraní původní z aktuální tabulky. Pokud v předchozích krocích nedošlo k žádným chybám, role pracovního procesu odstraní skrytou zprávu z fronty.

V tomto příkladu krok 4 vloží zaměstnance do tabulky Archiv . Může přidat zaměstnance do objektu blob ve službě Blob Service nebo do souboru v systému souborů.

Zotavení ze selhání

Je důležité, aby operace v krocích 4 a 5 byly idempotentní v případě, že role pracovního procesu potřebuje restartovat operaci archivace. Pokud používáte službu Table Service, v kroku 4 byste měli použít operaci vložení nebo nahrazení. V kroku 5 byste měli použít operaci odstranit, pokud existuje, v klientské knihovně, kterou používáte. Pokud používáte jiný systém úložiště, musíte použít příslušnou operaci idempotentní.

Pokud role pracovního procesu nikdy nedokončí krok 6, po vypršení časového limitu se zpráva znovu zobrazí ve frontě připravené pro roli pracovního procesu, aby se ji pokusila znovu zpracovat. Role pracovního procesu může zkontrolovat, kolikrát byla zpráva ve frontě přečtena, a v případě potřeby ji označit příznakem "jed" pro šetření odesláním do samostatné fronty. Další informace o čtení zpráv fronty a kontrole počtu vyřazení z fronty naleznete v tématu Získání zpráv.

Některé chyby ze služeb Table a Queue jsou přechodné chyby a vaše klientská aplikace by měla obsahovat vhodnou logiku opakování pro jejich zpracování.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Toto řešení neposkytuje izolaci transakcí. Klient může například číst tabulky Aktuální a Archiv , když byla role pracovního procesu mezi kroky 4 a 5, a zobrazit nekonzistentní zobrazení dat. Data budou nakonec konzistentní.
  • Abyste zajistili konečnou konzistenci, musíte mít jistotu, že kroky 4 a 5 jsou idempotentní.
  • Řešení můžete škálovat pomocí několika front a instancí rolí pracovního procesu.

Kdy se má tento model použít

Tento vzor použijte, pokud chcete zaručit konečnou konzistenci mezi entitami, které existují v různých oddílech nebo tabulkách. Tento model můžete rozšířit, abyste zajistili konečnou konzistenci operací napříč tabulkovou službou a službou Blob a dalšími zdroji dat mimo Azure Storage, jako je databáze nebo systém souborů.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Poznámka:

Pokud je izolace transakcí pro vaše řešení důležitá, měli byste zvážit změnu návrhu tabulek, abyste mohli používat EGT.

Model indexovacích entit

Udržujte entity indexu, které umožňují efektivní vyhledávání, která vracejí seznamy entit.

Kontext a problém

Služba Table service automaticky indexuje entity pomocí hodnot PartitionKey a RowKey . To umožňuje klientské aplikaci efektivně načíst entitu pomocí dotazu bodu. Například pomocí struktury tabulky uvedené níže může klientská aplikace efektivně načíst jednotlivou entitu zaměstnance pomocí názvu oddělení a ID zaměstnance ( PartitionKey a RowKey).

Graphic of employee entity structure where a client application can efficiently retrieve an individual employee entity by using the department name and the employee ID (the PartitionKey and RowKey).

Pokud chcete mít také možnost načíst seznam entit zaměstnanců na základě hodnoty jiné vlastnosti, která není jedinečná, například jejich příjmení, musíte použít méně efektivní kontrolu oddílů, abyste našli shody, a ne pomocí indexu je vyhledat přímo. Důvodem je to, že služba Table Service neposkytuje sekundární indexy.

Řešení

Pokud chcete povolit vyhledávání podle příjmení se strukturou entit, která je uvedená výše, musíte udržovat seznamy ID zaměstnanců. Pokud chcete načíst entity zaměstnanců s konkrétním příjmením, například Jonesem, musíte nejprve vyhledat seznam ID zaměstnanců pro zaměstnance s Jonesem jako příjmení a pak tyto entity zaměstnanců načíst. Existují tři hlavní možnosti pro ukládání seznamů ID zaměstnanců:

  • Použijte úložiště objektů blob.
  • Vytvořte entity indexu ve stejném oddílu jako entity zaměstnanců.
  • Vytvořte entity indexu v samostatném oddílu nebo tabulce.

Možnost č. 1: Použití úložiště objektů blob

Pro první možnost vytvoříte objekt blob pro každé jedinečné příjmení a v každém objektu blob uložíte seznam hodnot PartitionKey (oddělení) a RowKey (ID zaměstnance) pro zaměstnance, kteří mají toto příjmení. Když přidáte nebo odstraníte zaměstnance, měli byste zajistit, aby obsah příslušného objektu blob byl nakonec konzistentní s entitami zaměstnance.

Možnost č. 2: Vytvoření entit indexu ve stejném oddílu

Pro druhou možnost použijte entity indexu, které ukládají následující data:

Graphic showing employee entity, with string containing a list of employee IDs with same last name

Vlastnost EmployeeIDs obsahuje seznam ID zaměstnanců pro zaměstnance s příjmením uloženým v RowKey.

Následující kroky popisují proces, který byste měli provést při přidávání nového zaměstnance, pokud používáte druhou možnost. V tomto příkladu přidáváme zaměstnance s ID 000152 a příjmením Jones v prodejním oddělení:

  1. Načtěte entitu indexu s hodnotou PartitionKey "Sales" a hodnotou RowKey "Jones". Uložte značku ETag této entity, abyste ji mohli použít v kroku 2.
  2. Vytvořte transakci skupiny entit (tj. dávkovou operaci), která vloží novou entitu zaměstnance (hodnota PartitionKey "Sales" a RowKey hodnota "000152") a aktualizuje entitu indexu (hodnota PartitionKey "Sales" a RowKey value "Jones") přidáním nového ID zaměstnance do seznamu v poli EmployeeID. Další informace o transakcích skupin entit naleznete v tématu Transakce skupiny entit.
  3. Pokud transakce skupiny entit selže kvůli chybě optimistické souběžnosti (někdo jiný právě upravil entitu indexu), musíte začít znovu v kroku 1.

Podobný přístup můžete použít k odstranění zaměstnance, pokud používáte druhou možnost. Změna příjmení zaměstnance je o něco složitější, protože budete muset provést transakci skupiny entit, která aktualizuje tři entity: entitu zaměstnance, entitu indexu pro staré příjmení a entitu indexu pro nové příjmení. Před provedením jakýchkoli změn je nutné načíst každou entitu, abyste mohli načíst hodnoty značky ETag, které pak můžete použít k provádění aktualizací pomocí optimistické souběžnosti.

Následující kroky popisují proces, který byste měli postupovat, když potřebujete vyhledat všechny zaměstnance se zadaným příjmením v oddělení, pokud používáte druhou možnost. V tomto příkladu vyhledáme všechny zaměstnance s příjmením Jones v prodejním oddělení:

  1. Načtěte entitu indexu s hodnotou PartitionKey "Sales" a hodnotou RowKey "Jones".
  2. Parsujte seznam ID zaměstnanců v poli Id zaměstnance.
  3. Pokud potřebujete další informace o každém z těchto zaměstnanců (například jejich e-mailových adres), načtěte všechny entity zaměstnanců pomocí hodnoty PartitionKey "Sales" a RowKey ze seznamu zaměstnanců, které jste získali v kroku 2.

Možnost č. 3: Vytvoření entit indexu v samostatném oddílu nebo tabulce

Pro třetí možnost použijte entity indexu, které ukládají následující data:

Screenshot that shows the Employee index entity that contains a list of employee IDs for employees with the last name stored in the RowKey and PartitionKey.

Vlastnost EmployeeDetails obsahuje seznam ID zaměstnanců a párů názvů oddělení pro zaměstnance s příjmením uloženým v objektu RowKey.

Třetí možností není možné použít EGT k zachování konzistence, protože entity indexu jsou v samostatném oddílu od entit zaměstnanců. Ujistěte se, že entity indexu jsou nakonec konzistentní s entitami zaměstnanců.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Toto řešení vyžaduje alespoň dva dotazy k načtení odpovídajících entit: jeden k dotazování entit indexu, aby získal seznam hodnot RowKey , a potom dotazy k načtení každé entity v seznamu.
  • Vzhledem k tomu, že jednotlivá entita má maximální velikost 1 MB, možnost 2 a možnost #3 v řešení předpokládají, že seznam ID zaměstnanců pro každé příjmení není nikdy větší než 1 MB. Pokud bude seznam ID zaměstnanců pravděpodobně větší než 1 MB, použijte možnost 1 a uložte data indexu do úložiště objektů blob.
  • Pokud použijete možnost č. 2 (pomocí EGT ke zpracování přidávání a odstraňování zaměstnanců a změně příjmení zaměstnance), musíte vyhodnotit, jestli se objem transakcí bude v daném oddílu blížit limitům škálovatelnosti. V takovém případě byste měli zvážit nakonec konzistentní řešení (možnost 1 nebo možnost #3), které používá fronty ke zpracování žádostí o aktualizaci a umožňuje ukládat entity indexu do samostatného oddílu od entit zaměstnanců.
  • Možnost č. 2 v tomto řešení předpokládá, že chcete vyhledat příjmení v rámci oddělení: například chcete načíst seznam zaměstnanců s příjmením Jones v prodejním oddělení. Pokud chcete mít možnost vyhledat všechny zaměstnance s příjmením Jones v celé organizaci, použijte možnost č. 1 nebo možnost č. 3.
  • Můžete implementovat řešení založené na frontě, které zajišťuje konečnou konzistenci (další podrobnosti najdete v modelu nakonec konzistentní transakce).

Kdy se má tento model použít

Tento vzor použijte, když chcete vyhledat sadu entit, které sdílejí společnou hodnotu vlastnosti, například všichni zaměstnanci s příjmením Jones.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Model denormalizace

Zkombinujte související data v jedné entitě, abyste mohli načíst všechna potřebná data pomocí dotazu s jedním bodem.

Kontext a problém

V relační databázi obvykle normalizujete data, aby se odebrala duplicita, což vede k dotazům, které načítají data z více tabulek. Pokud normalizujete data v tabulkách Azure, musíte provést několik cest z klienta na server, aby se načetla související data. Například s tabulkovou strukturou uvedenou níže potřebujete dvě zpáteční cesty k načtení podrobností pro oddělení: jedna pro načtení entity oddělení, která obsahuje ID manažera, a další požadavek na načtení podrobností manažera v entitě zaměstnance.

Graphic of department entity and employee entity

Řešení

Místo uložení dat ve dvou samostatných entitách denormalizovat data a ponechat kopii podrobností manažera v entitě oddělení. Příklad:

Graphic of denormalized and combined department entity

U entit oddělení uložených s těmito vlastnostmi teď můžete pomocí dotazu bodu načíst všechny podrobnosti, které potřebujete o oddělení.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Při ukládání některých dat dvakrát dochází k nákladovým režijním nákladům. Výhoda výkonu (vyplývající z méně požadavků na službu úložiště) obvykle převáží mezní zvýšení nákladů na úložiště (a tyto náklady jsou částečně posunovány snížením počtu transakcí, které potřebujete k načtení podrobností o oddělení).
  • Je nutné zachovat konzistenci dvou entit, které ukládají informace o manažerech. Problém s konzistencí můžete vyřešit tak, že pomocí EGT aktualizujete více entit v jedné atomické transakci: v tomto případě se entita oddělení a entita zaměstnance vedoucího oddělení ukládají do stejného oddílu.

Kdy se má tento model použít

Tento vzor použijte, když často potřebujete vyhledat související informace. Tento model snižuje počet dotazů, které musí klient provést, aby bylo možné načíst data, která vyžaduje.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Vzor složeného klíče

Pomocí složených hodnot RowKey povolte klientovi vyhledávání souvisejících dat pomocí dotazu s jedním bodem.

Kontext a problém

V relační databázi je přirozené použít spojení v dotazech k vrácení souvisejících částí dat klientovi v jednom dotazu. Pomocí ID zaměstnance můžete například vyhledat seznam souvisejících entit, které obsahují údaje o výkonu a kontrole pro daného zaměstnance.

Předpokládejme, že ukládáte entity zaměstnanců ve službě Table Service pomocí následující struktury:

Graphic of employee entity structure you should use to store employee entities in Table storage.

Musíte také ukládat historická data týkající se kontrol a výkonu za každý rok, kdy zaměstnanec pracoval ve vaší organizaci a potřebujete mít přístup k tomuto informacím po roce. Jednou z možností je vytvořit další tabulku, která ukládá entity s následující strukturou:

Graphic of employee review entity

Všimněte si, že s tímto přístupem se můžete rozhodnout duplikovat některé informace (například jméno a příjmení) v nové entitě, abyste mohli načíst data jediným požadavkem. Nelze však zachovat silnou konzistenci, protože nelze použít EGT k aktualizaci dvou entit atomicky.

Řešení

Uložte nový typ entity v původní tabulce pomocí entit s následující strukturou:

Graphic of employee entity with compound key

Všimněte si, že RowKey je teď složený klíč složený z ID zaměstnance a roku dat kontroly, která vám umožní načíst výkon zaměstnance a zkontrolovat data pomocí jediné žádosti o jednu entitu.

Následující příklad popisuje, jak můžete načíst všechna data kontroly pro konkrétního zaměstnance (například 000123 zaměstnance v prodejním oddělení):

$filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000123') a (RowKey lt '000123_2012')&$select=RowKey,Manager Rating,Peer Rating,Comments

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Měli byste použít vhodný znak oddělovače, který usnadňuje analýzu hodnoty RowKey : například 000123_2012.
  • Tuto entitu také ukládáte do stejného oddílu jako jiné entity, které obsahují související data pro stejného zaměstnance, což znamená, že pomocí EGT můžete zachovat silnou konzistenci.
  • Měli byste zvážit, jak často budete dotazovat data, abyste zjistili, jestli je tento vzor vhodný. Pokud například budete k datům kontroly přistupovat zřídka a hlavní data zaměstnanců často byste je měli uchovávat jako samostatné entity.

Kdy se má tento model použít

Tento vzor použijte, když potřebujete uložit jednu nebo více souvisejících entit, které často dotazujete.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Log tail pattern

Načtěte n entit, které byly naposledy přidány do oddílu, pomocí hodnoty RowKey, která seřadí v obráceném pořadí data a času.

Kontext a problém

Běžným požadavkem je možnost načíst naposledy vytvořené entity, například 10 nejnovějších žádostí o výdaje odeslané zaměstnancem. Dotazy na tabulky podporují operaci dotazu $top pro vrácení prvních n entit ze sady: neexistuje žádná ekvivalentní operace dotazu pro vrácení posledních n entit v sadě.

Řešení

Ukládejte entity pomocí RowKey , které přirozeně řadí v obráceném pořadí data a času, takže poslední položka je vždy první položka v tabulce.

Pokud například chcete mít možnost načíst 10 nejnovějších žádostí o výdaje odeslané zaměstnancem, můžete použít hodnotu zpětného zaškrtnutí odvozenou od aktuálního data a času. Následující ukázka kódu jazyka C# ukazuje jeden ze způsobů, jak vytvořit vhodnou hodnotu "inverted ticks" pro RowKey , která seřadí od nejnovějšího po nejstarší:

string invertedTicks = string.Format("{0:D19}", DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks);

K hodnotě data a času se můžete vrátit pomocí následujícího kódu:

DateTime dt = new DateTime(DateTime.MaxValue.Ticks - Int64.Parse(invertedTicks));

Dotaz tabulky vypadá takto:

https://myaccount.table.core.windows.net/EmployeeExpense(PartitionKey='empid')?$top=10

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Pokud chcete zajistit, aby se řetězcová hodnota seřadil podle očekávání, musíte hodnotu zpětného škrtu vyřadit s počátečními nulami.
  • Musíte znát cíle škálovatelnosti na úrovni oddílu. Dávejte pozor, abyste nevytvořli oddíly s horkým místem.

Kdy se má tento model použít

Tento vzor použijte v případě, že potřebujete získat přístup k entitě v obráceném pořadí data a času nebo když potřebujete získat přístup k naposledy přidanou entitě.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Model odstranění velkého objemu

Povolení odstranění velkého objemu entit uložením všech entit pro současné odstranění ve vlastní samostatné tabulce; entity odstraníte odstraněním tabulky.

Kontext a problém

Mnoho aplikací odstraňuje stará data, která už nemusí být dostupná pro klientskou aplikaci nebo že se aplikace archivovala na jiné médium úložiště. Tato data obvykle identifikujete podle data: například potřebujete odstranit záznamy všech žádostí o přihlášení, které jsou starší než 60 dnů.

Jedním z možných návrhů je použití data a času žádosti o přihlášení v RowKey:

Graphic of login attempt entity

Tento přístup zabraňuje hotspotům oddílů, protože aplikace může vkládat a odstraňovat přihlašovací entity pro každého uživatele v samostatném oddílu. Tento přístup ale může být nákladný a časově náročný, pokud máte velký počet entit, protože nejprve potřebujete provést kontrolu tabulky, abyste identifikovali všechny entity, které se mají odstranit, a pak musíte odstranit každou starou entitu. Počet odezvy na server potřebný k odstranění starých entit můžete snížit tak, že do egtů zasáhnete více žádostí o odstranění.

Řešení

Pro každý den pokusů o přihlášení použijte samostatnou tabulku. Výše uvedený návrh entity můžete použít, abyste se vyhnuli hotspotům při vkládání entit a odstranění starých entit je teď jednoduše otázkou odstranění jedné tabulky každý den (jedna operace úložiště) místo toho, abyste každý den našli a odstranili stovky a tisíce jednotlivých přihlašovacích entit.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Podporuje návrh jiné způsoby, jak bude vaše aplikace používat data, jako je vyhledávání konkrétních entit, propojení s jinými daty nebo generování agregovaných informací?
  • Vyhnete se návrhu při vkládání nových entit horkým místům?
  • Pokud chcete po odstranění tabulky znovu použít stejný název tabulky, počítejte se zpožděním. Lepší je vždy používat jedinečné názvy tabulek.
  • Při prvním použití nové tabulky počítejte s omezením, zatímco služba Table Service zjišťuje vzory přístupu a distribuuje oddíly mezi uzly. Měli byste zvážit, jak často potřebujete vytvářet nové tabulky.

Kdy se má tento model použít

Tento vzor použijte, pokud máte velký objem entit, které musíte odstranit současně.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Model datových řad

Uložte úplnou datovou řadu do jedné entity, abyste minimalizovali počet požadavků, které provedete.

Kontext a problém

Běžným scénářem je, aby aplikace ukládala řadu dat, která obvykle potřebuje načíst najednou. Vaše aplikace může například zaznamenat, kolik zpráv rychlých zpráv každý zaměstnanec odesílá každou hodinu, a pak pomocí těchto informací vykreslit, kolik zpráv každý uživatel odeslal za předchozích 24 hodin. Jedním z návrhů může být uložení 24 entit pro každého zaměstnance:

Graphic of message stats entity

Díky tomuto návrhu můžete entitu snadno vyhledat a aktualizovat tak, aby se aktualizovala pro každého zaměstnance, kdykoli aplikace potřebuje aktualizovat hodnotu počtu zpráv. Pokud ale chcete načíst informace pro vykreslení grafu aktivity za předchozích 24 hodin, musíte načíst 24 entit.

Řešení

Pomocí následujícího návrhu s samostatnou vlastností uložte počet zpráv za každou hodinu:

Graphic showing message stats entity with separated properties

Pomocí tohoto návrhu můžete pomocí operace sloučení aktualizovat počet zpráv pro zaměstnance za určitou hodinu. Teď můžete načíst všechny informace, které potřebujete k vykreslení grafu, pomocí požadavku na jednu entitu.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Pokud se úplná datová řada nevejde do jedné entity (entita může mít až 252 vlastností), použijte alternativní úložiště dat, jako je například objekt blob.
  • Pokud máte více klientů, kteří entitu aktualizují současně, budete muset pomocí značky ETag implementovat optimistickou souběžnost. Pokud máte mnoho klientů, může docházet k vysokému kolizím.

Kdy se má tento model použít

Tento vzor použijte, když potřebujete aktualizovat a načíst datovou řadu přidruženou k jednotlivé entitě.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Vzor širokých entit

K uložení logických entit s více než 252 vlastnostmi použijte více fyzických entit.

Kontext a problém

Jednotlivá entita může mít maximálně 252 vlastností (s výjimkou povinných systémových vlastností) a nemůže uložit celkem více než 1 MB dat. V relační databázi byste obvykle zaokrouhlili jakákoli omezení velikosti řádku přidáním nové tabulky a vynucováním relace 1:1 mezi nimi.

Řešení

Pomocí služby Table Service můžete uložit více entit, které představují jeden velký obchodní objekt s více než 252 vlastnostmi. Pokud například chcete uložit počet zpráv rychlých zpráv odeslaných jednotlivými zaměstnanci za posledních 365 dnů, můžete použít následující návrh, který používá dvě entity s různými schématy:

Graphic showing message stats entity with Rowkey 01 and message stats entity with Rowkey 02

Pokud potřebujete provést změnu, která vyžaduje aktualizaci obou entit, aby byly vzájemně synchronizované, můžete použít EGT. V opačném případě můžete pomocí jedné operace sloučení aktualizovat počet zpráv pro konkrétní den. Pokud chcete načíst všechna data pro jednotlivého zaměstnance, musíte načíst obě entity, které můžete provést se dvěma efektivními požadavky, které používají hodnotu PartitionKey i RowKey .

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Načtení úplné logické entity zahrnuje alespoň dvě transakce úložiště: jednu pro načtení každé fyzické entity.

Kdy se má tento model použít

Tento vzor použijte, když potřebujete uložit entity, jejichž velikost nebo počet vlastností překročí limity pro jednotlivé entity ve službě Table Service.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Model velkých entit

Úložiště objektů blob použijte k ukládání velkých hodnot vlastností.

Kontext a problém

Jednotlivá entita nemůže celkem ukládat více než 1 MB dat. Pokud jedna nebo několik vlastností ukládá hodnoty, které způsobují, že celková velikost entity tuto hodnotu překročí, nelze uložit celou entitu ve službě Table Service.

Řešení

Pokud vaše entita přesahuje velikost 1 MB, protože jedna nebo více vlastností obsahuje velké množství dat, můžete data uložit ve službě Blob Service a pak uložit adresu objektu blob ve vlastnosti v entitě. Můžete například uložit fotku zaměstnance do úložiště objektů blob a uložit odkaz na fotku ve vlastnosti Fotka entity zaměstnance:

Graphic showing employee entity with string for Photo pointing to Blob storage

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Chcete-li zachovat konečnou konzistenci mezi entitou ve službě Table Service a daty ve službě Blob, použijte k údržbě entit vzor transakcí konzistentních s konečnou konzistencí.
  • Načtení úplné entity zahrnuje alespoň dvě transakce úložiště: jednu pro načtení entity a jednu pro načtení dat objektu blob.

Kdy se má tento model použít

Tento vzor použijte, když potřebujete uložit entity, jejichž velikost překračuje limity pro jednotlivé entity ve službě Table Service.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Předpřipravený/přidávací anti-pattern

Zvyšte škálovatelnost, pokud máte velký objem vložení rozložením vložení do více oddílů.

Kontext a problém

Předpending nebo připojení entit k uloženým entitám obvykle vede k tomu, že aplikace přidává nové entity do prvního nebo posledního oddílu posloupnosti oddílů. V takovém případě se všechny vložení v daném okamžiku provádějí ve stejném oddílu, čímž se vytvoří hotspot, který brání službě Table Service v vyrovnávání zatížení vkládání mezi více uzlů a pravděpodobně způsobí, že vaše aplikace dosáhne cílů škálovatelnosti pro oddíl. Pokud máte například aplikaci, která protokoluje síťový přístup a přístup k prostředkům zaměstnancům, pak struktura entit, jak je znázorněno níže, může vést k tomu, že oddíl aktuální hodiny se stane hotspotem, pokud objem transakcí dosáhne cíle škálovatelnosti pro jednotlivé oddíly:

Entity structure

Řešení

Následující alternativní struktura entit zabraňuje hotspotu u každého konkrétního oddílu, protože události protokolu aplikace:

Alternative entity structure

Všimněte si, že v tomto příkladu jsou složené klíče Jak PartitionKey, tak RowKey. Klíč oddílu používá id oddělení i zaměstnance k distribuci protokolování mezi více oddílů.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

  • Podporuje alternativní struktura klíčů, která zabraňuje efektivnímu vytváření horkých oddílů při vkládání dotazů, které vaše klientská aplikace provádí?
  • Znamená váš očekávaný objem transakcí, že pravděpodobně dosáhnete cílů škálovatelnosti pro jednotlivé oddíly a omezíte je službou úložiště?

Kdy se má tento model použít

Vyhněte se předpřipravenému nebo přidávacímu anti-vzoru, pokud je pravděpodobné, že objem transakcí způsobí omezování službou úložiště při přístupu k horkému oddílu.

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

Anti-pattern dat protokolu

K ukládání dat protokolu byste obvykle měli použít službu Blob Service místo služby Table Service.

Kontext a problém

Běžným případem použití dat protokolu je načtení výběru položek protokolu pro konkrétní rozsah data a času: například chcete najít všechny chybové a kritické zprávy, které vaše aplikace protokolovala od 15:04 do 15:06 k určitému datu. Nechcete použít datum a čas zprávy protokolu k určení oddílu, do kterého ukládáte entity protokolu: výsledkem je horký oddíl, protože v daném okamžiku budou všechny entity protokolu sdílet stejnou hodnotu PartitionKey (viz oddíl Prepend/append anti-pattern). Například následující schéma entity pro zprávu protokolu vede k horkému oddílu, protože aplikace zapisuje všechny zprávy protokolu do oddílu pro aktuální datum a hodinu:

Log message entity

V tomto příkladu rowKey obsahuje datum a čas zprávy protokolu, aby se zajistilo, že zprávy protokolu jsou uloženy seřazené v pořadí data a času a obsahuje ID zprávy pro případ, že více zpráv protokolu sdílí stejné datum a čas.

Dalším přístupem je použití PartitionKey , který zajišťuje, že aplikace zapisuje zprávy v rozsahu oddílů. Pokud například zdroj zprávy protokolu poskytuje způsob distribuce zpráv napříč mnoha oddíly, můžete použít následující schéma entity:

Alternative log message entity

Problém s tímto schématem však spočívá v tom, že k načtení všech zpráv protokolu pro určité časové období je nutné prohledat všechny oddíly v tabulce.

Řešení

Předchozí část zdůraznila problém při pokusu o použití služby Table service k ukládání položek protokolu a navrhl dva návrhy, neuspokojivé návrhy. Jedno řešení vedlo k horkému oddílu s rizikem nízkého výkonu zápisu zpráv protokolu; Druhé řešení vedlo k nízkému výkonu dotazů z důvodu požadavku na prohledávání každého oddílu v tabulce za účelem načtení zpráv protokolu za určité časové období. Úložiště objektů blob nabízí lepší řešení pro tento typ scénáře. Azure Analýza úložiště ukládá data protokolů, která shromažďuje.

Tato část popisuje, jak Analýza úložiště ukládá data protokolů do úložiště objektů blob jako ilustraci tohoto přístupu k ukládání dat, která obvykle dotazujete podle rozsahu.

Analýza úložiště ukládá zprávy protokolu ve formátu s oddělovači ve více objektech blob. Formát s oddělovači usnadňuje klientské aplikaci parsování dat ve zprávě protokolu.

Analýza úložiště používá pro objekty blob zásady vytváření názvů, které umožňují vyhledat objekt blob (nebo objekty blob), které obsahují zprávy protokolu, pro které hledáte. Například objekt blob s názvem queue/2014/07/31/1800/000001.log obsahuje zprávy protokolu, které se vztahují ke službě fronty za hodinu počínaje 18:00 31. července 2014. "000001" označuje, že se jedná o první soubor protokolu pro toto období. Analýza úložiště také zaznamenává časová razítka prvních a posledních zpráv protokolu uložených v souboru jako součást metadat objektu blob. Rozhraní API pro úložiště objektů blob umožňuje vyhledat objekty blob v kontejneru na základě předpony názvu: k vyhledání všech objektů blob, které obsahují data protokolu fronty za hodinu počínaje 18:00, můžete použít předponu Queue/2014/07/31/1800.

Analýza úložiště interně ukládat zprávy protokolu do vyrovnávací paměti a pak pravidelně aktualizuje příslušný objekt blob nebo vytvoří nový s nejnovější dávkou položek protokolu. Tím se sníží počet zápisů, které musí provádět ve službě Blob Service.

Pokud implementujete podobné řešení ve vlastní aplikaci, musíte zvážit, jak spravovat kompromis mezi spolehlivostí (zápis každé položky protokolu do úložiště objektů blob, jak se to stane) a náklady a škálovatelnost (ukládání aktualizací do vyrovnávací paměti ve vaší aplikaci a jejich zápis do úložiště objektů blob v dávkách).

Problémy a důležité informace

Při rozhodování o ukládání dat protokolu zvažte následující body:

  • Pokud vytvoříte návrh tabulky, který zabrání potenciálním horkým oddílům, můžete zjistit, že k datům protokolu nemůžete efektivně přistupovat.
  • Ke zpracování dat protokolu klient často potřebuje načíst mnoho záznamů.
  • I když jsou data protokolů často strukturovaná, úložiště objektů blob může být lepším řešením.

Na co myslet při implementaci

Tato část popisuje některé aspekty, které je potřeba vzít v úvahu při implementaci vzorů popsaných v předchozích částech. Většina z této části používá příklady napsané v jazyce C#, které používají klientskou knihovnu služby Storage (verze 4.3.0 v době psaní).

Načítání entit

Jak je popsáno v části Návrh pro dotazování, nejúčinnějším dotazem je bodový dotaz. V některých scénářích ale možná budete muset načíst více entit. Tato část popisuje některé běžné přístupy k načítání entit pomocí klientské knihovny služby Storage.

Spuštění dotazu bodu pomocí klientské knihovny služby Storage

Nejjednodušší způsob, jak spustit bodový dotaz, je použít metodu GetEntityAsync , jak je znázorněno v následujícím fragmentu kódu jazyka C#, který načte entitu s hodnotou PartitionKey hodnoty Sales a RowKey hodnoty 212:

EmployeeEntity employee = await employeeTable.GetEntityAsync<EmployeeEntity>("Sales", "212");

Všimněte si, jak tento příklad očekává, že entita, kterou načítá, bude typu EmployeeEntity.

Načítání více entit pomocí LINQ

LinQ můžete použít k načtení více entit z table service při práci se standardní knihovnou tabulek Microsoft Azure Cosmos DB.

dotnet add package Azure.Data.Tables

Aby následující příklady fungovaly, budete muset zahrnout obory názvů:

using System.Linq;
using Azure.Data.Tables

Načtení více entit lze dosáhnout zadáním dotazu s klauzulí filtru . Abyste se vyhnuli prohledávání tabulek, měli byste vždy zahrnout hodnotu PartitionKey do klauzule filtru a pokud je to možné , hodnota RowKey , aby se zabránilo prohledávání tabulek a oddílů. Služba Table Service podporuje omezenou sadu relačních operátorů (větší než, větší než nebo rovno, menší než, menší nebo rovno, rovno a nerovná) pro použití v klauzuli filtru.

V následujícím příkladu employeeTableje objekt TableClient . Tento příklad najde všechny zaměstnance, jejichž příjmení začíná na "B" (za předpokladu, že RowKey ukládá příjmení) v prodejním oddělení (za předpokladu, že PartitionKey ukládá název oddělení):

var employees = employeeTable.Query<EmployeeEntity>(e => (e.PartitionKey == "Sales" && e.RowKey.CompareTo("B") >= 0 && e.RowKey.CompareTo("C") < 0));  

Všimněte si, že dotaz určuje jak RowKey , tak PartitionKey , aby byl zajištěn lepší výkon.

Následující ukázka kódu ukazuje ekvivalentní funkce bez použití syntaxe LINQ:

var employees = employeeTable.Query<EmployeeEntity>(filter: $"PartitionKey eq 'Sales' and RowKey ge 'B' and RowKey lt 'C'");  

Poznámka:

Ukázkové metody dotazu zahrnují tři podmínky filtru.

Načítání velkého počtu entit z dotazu

Optimální dotaz vrátí jednotlivou entitu na základě hodnoty PartitionKey a hodnoty RowKey . V některých scénářích ale možná budete muset vrátit mnoho entit ze stejného oddílu nebo dokonce z mnoha oddílů.

V takových scénářích byste měli vždy plně otestovat výkon aplikace.

Dotaz na službu Table Service může najednou vrátit maximálně 1 000 entit a může se spustit maximálně pět sekund. Pokud sada výsledků obsahuje více než 1 000 entit, pokud se dotaz nedokončil během pěti sekund nebo pokud dotaz překročí hranici oddílu, vrátí služba Table service token pokračování, který klientské aplikaci umožní vyžádat další sadu entit. Další informace o tom, jak fungují tokeny pokračování, najdete v tématu Vypršení časového limitu dotazu a stránkování.

Pokud používáte klientskou knihovnu Azure Tables, může automaticky zpracovat tokeny pokračování za vás, protože vrací entity ze služby Table Service. Následující ukázka kódu jazyka C# pomocí klientské knihovny automaticky zpracuje tokeny pokračování, pokud je služba Table Service vrátí v odpovědi:

var employees = employeeTable.Query<EmployeeEntity>("PartitionKey eq 'Sales'")

foreach (var emp in employees)
{
    // ...
}  

Můžete také zadat maximální počet entit, které se vrátí na stránku. Následující příklad ukazuje, jak dotazovat entity pomocí maxPerPage:

var employees = employeeTable.Query<EmployeeEntity>(maxPerPage: 10);

// Iterate the Pageable object by page
foreach (var page in employees.AsPages())
{
    // Iterate the entities returned for this page
    foreach (var emp in page.Values)
    {
        // ...
    }
}

V pokročilejších scénářích můžete chtít uložit token pro pokračování vrácený ze služby tak, aby váš kód přesně kontroloval, kdy se načítají další stránky. Následující příklad ukazuje základní scénář, jak lze token načíst a použít u stránkovaných výsledků:

string continuationToken = null;
bool moreResultsAvailable = true;
while (moreResultsAvailable)
{
    var page = employeeTable
        .Query<EmployeeEntity>()
        .AsPages(continuationToken, pageSizeHint: 10)
        .FirstOrDefault(); // pageSizeHint limits the number of results in a single page, so we only enumerate the first page

    if (page == null)
        break;

    // Get the continuation token from the page
    // Note: This value can be stored so that the next page query can be executed later
    continuationToken = page.ContinuationToken;

    var pageResults = page.Values;
    moreResultsAvailable = pageResults.Any() && continuationToken != null;

    // Iterate the results for this page
    foreach (var result in pageResults)
    {
        // ...
    }
} 

Pomocí tokenů pokračování můžete explicitně řídit, kdy aplikace načte další segment dat. Pokud například klientská aplikace umožňuje uživatelům stránkovat entity uložené v tabulce, uživatel se může rozhodnout, že nebude stránkovat všechny entity načtené dotazem, takže vaše aplikace použije token pro pokračování k načtení dalšího segmentu, když uživatel dokončil stránkování všech entit v aktuálním segmentu. Tento přístup má několik výhod:

  • Umožňuje omezit množství dat, která se mají načítat ze služby Table Service a která se přesouvají přes síť.
  • Umožňuje provádět asynchronní vstupně-výstupní operace v .NET.
  • Umožňuje serializovat token pokračování do trvalého úložiště, abyste mohli pokračovat v případě chybového ukončení aplikace.

Poznámka:

Token pokračování obvykle vrací segment obsahující 1 000 entit, i když může být méně. To platí také v případě, že omezíte počet položek, které dotaz vrátí, pomocí příkazu Take vrátíte první n entit, které splňují kritéria vyhledávání: služba Table Service může vrátit segment obsahující méně než n entit spolu s tokenem pokračování, který vám umožní načíst zbývající entity.

Projekce na straně serveru

Jedna entita může mít až 255 vlastností a velikost až 1 MB. Při dotazování na tabulku a načítání entit možná nebudete potřebovat všechny vlastnosti a nemusíte zbytečně přenášet data (aby se snížila latence a náklady). K přenosu potřebných vlastností můžete použít projekce na straně serveru. Následující příklad načte pouze vlastnost Email (spolu s PartitionKey, RowKey, Timestamp a ETag) z entit vybraných dotazem.

var subsetResults  = query{
    for employee in employeeTable.Query<EmployeeEntity>("PartitionKey eq 'Sales'") do
    select employee.Email
}
foreach (var e in subsetResults)
{
    Console.WriteLine("RowKey: {0}, EmployeeEmail: {1}", e.RowKey, e.Email);
}  

Všimněte si, jak je hodnota RowKey dostupná, i když nebyla zahrnuta do seznamu vlastností, které se mají načíst.

Úprava entit

Klientská knihovna služby Storage umožňuje upravovat entity uložené ve službě Table Service vložením, odstraněním a aktualizací entit. Pomocí EGT můžete dosázet více operací vložení, aktualizace a odstraňování společně, abyste snížili požadovaný počet odezv a zlepšili výkon vašeho řešení.

Výjimky vyvolané, když klientská knihovna úložiště spustí EGT, obvykle zahrnují index entity, která způsobila selhání dávky. To je užitečné, když ladíte kód, který používá EGT.

Měli byste také zvážit, jak váš návrh ovlivňuje způsob, jakým klientská aplikace zpracovává operace souběžnosti a aktualizace.

Správa souběžnosti

Služba Table Service ve výchozím nastavení implementuje kontroly optimistické souběžnosti na úrovni jednotlivých entit operací Vložení, sloučení a odstranění , i když je možné, aby klient tyto kontroly vynechal. Další informace o tom, jak služba Table Service spravuje souběžnost, najdete v tématu Správa souběžnosti v Microsoft Azure Storage.

Sloučení nebo nahrazení

Metoda Replace třídy TableOperation vždy nahrazuje úplnou entitu ve službě Table Service. Pokud do požadavku nezahrnete vlastnost, pokud tato vlastnost existuje v uložené entitě, požadavek tuto vlastnost z uložené entity odebere. Pokud nechcete vlastnost z uložené entity explicitně odebrat, musíte do požadavku zahrnout každou vlastnost.

Metodu Merge třídy TableOperation můžete použít ke snížení množství dat, která odesíláte do služby Table Service, když chcete aktualizovat entitu. Metoda Merge nahrazuje všechny vlastnosti v uložené entitě hodnotami vlastností z entity zahrnuté v požadavku, ale ponechá nedotčené všechny vlastnosti uložené entity, které nejsou zahrnuty v požadavku. To je užitečné, pokud máte velké entity a potřebujete aktualizovat pouze malý počet vlastností v požadavku.

Poznámka:

Metody Replace a Merge selžou, pokud entita neexistuje. Alternativně můžete použít metody InsertOrReplace a InsertOrMerge , které vytvoří novou entitu, pokud neexistuje.

Práce s heterogenními typy entit

Služba Table Service je úložiště tabulek bez schématu, které znamená, že jedna tabulka může ukládat entity více typů a poskytuje tak ve vašem návrhu velkou flexibilitu. Následující příklad znázorňuje tabulku, která ukládá entity zaměstnanců i oddělení:

PartitionKey RowKey Časové razítko
FirstName LastName Věk E-mail
FirstName LastName Věk E-mail
DepartmentName EmployeeCount
FirstName LastName Věk E-mail

Každá entita musí mít stále hodnoty PartitionKey, RowKey a Timestamp , ale může mít libovolnou sadu vlastností. Kromě toho neexistuje nic, co by označí typ entity, pokud se nerozhodnete tyto informace uložit někam. Existují dvě možnosti identifikace typu entity:

  • Předpenpend typ entity na RowKey (nebo možná PartitionKey). Například EMPLOYEE_000123 nebo DEPARTMENT_SALES jako hodnoty RowKey .
  • K záznamu typu entity použijte samostatnou vlastnost, jak je znázorněno v tabulce níže.
PartitionKey RowKey Časové razítko
EntityType FirstName LastName Věk E-mail
Zaměstnanec
EntityType FirstName LastName Věk E-mail
Zaměstnanec
EntityType DepartmentName EmployeeCount
Oddělení
EntityType FirstName LastName Věk E-mail
Zaměstnanec

První možnost, předpřipravení typu entity na RowKey, je užitečná, pokud existuje možnost, že dvě entity různých typů mohou mít stejnou hodnotu klíče. Seskupuje také entity stejného typu v oddílu.

Techniky popisované v této části jsou zvláště relevantní pro diskuzi o vztazích dědičnosti dříve v tomto průvodci v článku Modelování relací.

Poznámka:

Měli byste zvážit zahrnutí čísla verze do hodnoty typu entity, aby klientské aplikace mohly vyvíjet objekty POCO a pracovat s různými verzemi.

Zbývající část této části popisuje některé funkce klientské knihovny služby Storage, které usnadňují práci s více typy entit ve stejné tabulce.

Načítání heterogenních typů entit

Pokud používáte klientskou knihovnu Table, máte tři možnosti pro práci s více typy entit.

Pokud znáte typ entity uložené s konkrétními hodnotami RowKey a PartitionKey , můžete při načtení entity určit typ entity, jak je znázorněno v předchozích dvou příkladech, které načítají entity typu EmployeeEntity: Spuštění dotazu typu Point Pomocí klientské knihovny úložiště a načítání více entit pomocí LINQ.

Druhou možností je použít typ TableEntity (taška vlastností) místo konkrétního typu entity POCO (tato možnost může také zlepšit výkon, protože není nutné serializovat a deserializovat entitu na typy .NET). Následující kód jazyka C# potenciálně načte více entit různých typů z tabulky, ale vrátí všechny entity jako instance TableEntity . Potom použije vlastnost EntityType k určení typu každé entity:

Pageable<TableEntity> entities = employeeTable.Query<TableEntity>(x =>
    x.PartitionKey ==  "Sales" && x.RowKey.CompareTo("B") >= 0 && x.RowKey.CompareTo("F") <= 0)

foreach (var entity in entities)
{
    if (entity.GetString("EntityType") == "Employee")
    {
        // use entityTypeProperty, RowKey, PartitionKey, Etag, and Timestamp
    }
}  

Chcete-li načíst další vlastnosti, je nutné použít GetString metoda u entity TableEntity třídy.

Úprava heterogenních typů entit

Abyste ji odstranili, nemusíte znát typ entity a při vložení vždy znáte typ entity. Typ TableEntity však můžete použít k aktualizaci entity bez znalosti jejího typu a bez použití třídy entit POCO. Následující ukázka kódu načte jednu entitu a před aktualizací zkontroluje, jestli vlastnost EmployeeCount existuje.

var result = employeeTable.GetEntity<TableEntity>(partitionKey, rowKey);
TableEntity department = result.Value;
if (department.GetInt32("EmployeeCount") == null)
{
    throw new InvalidOperationException("Invalid entity, EmployeeCount property not found.");
}
 employeeTable.UpdateEntity(department, ETag.All, TableUpdateMode.Merge);

Řízení přístupu pomocí sdílených přístupových podpisů

Tokeny sdíleného přístupového podpisu (SAS) můžete použít k tomu, aby klientské aplikace mohly upravovat (a dotazovat) entity tabulek, aniž byste museli do kódu zahrnout klíč vašeho účtu úložiště. Používání sdíleného přístupového podpisu ve vaší aplikaci obvykle přináší tři hlavní výhody:

  • Klíč účtu úložiště nemusíte distribuovat na nezabezpečenou platformu (například mobilní zařízení), aby toto zařízení mohlo přistupovat k entitě ve službě Table Service a upravovat je.
  • Některé z úloh, které webové role a role pracovních procesů provádějí při správě entit, můžete přesměrovat na klientská zařízení, jako jsou počítače koncových uživatelů a mobilní zařízení.
  • Klientovi můžete přiřadit omezenou a časově omezenou sadu oprávnění (například povolit přístup jen pro čtení ke konkrétním prostředkům).

Další informace o používání tokenů SAS se službou Table Service naleznete v tématu Použití sdílených přístupových podpisů (SAS).

Přesto však musíte vygenerovat tokeny SAS, které udělují klientské aplikaci entitám v tabulkové službě: Měli byste to udělat v prostředí, které má zabezpečený přístup k klíčům účtu úložiště. Obvykle používáte webovou roli nebo roli pracovního procesu k vygenerování tokenů SAS a jejich doručování klientským aplikacím, které potřebují přístup k vašim entitám. Vzhledem k tomu, že při generování a doručování tokenů SAS klientům stále dochází k režii, měli byste zvážit, jak nejlépe snížit tuto režii, zejména ve scénářích s velkým objemem.

Token SAS, který uděluje přístup k podmnožině entit v tabulce, je možné vygenerovat. Ve výchozím nastavení vytvoříte token SAS pro celou tabulku, ale je také možné určit, že token SAS udělí přístup k rozsahu hodnot PartitionKey nebo rozsah hodnot PartitionKey a RowKey . Můžete se rozhodnout generovat tokeny SAS pro jednotlivé uživatele systému tak, aby token SAS každého uživatele umožňoval přístup pouze k jejich vlastním entitám v tabulkové službě.

Asynchronní a paralelní operace

Za předpokladu, že požadavky rozprostíráte do více oddílů, můžete zvýšit propustnost a rychlost odezvy klientů pomocí asynchronních nebo paralelních dotazů. Můžete mít například dvě nebo více instancí rolí pracovního procesu, které přistupují k tabulkám paralelně. Můžete mít jednotlivé role pracovního procesu zodpovědné za konkrétní sady oddílů nebo jednoduše mít více instancí rolí pracovního procesu, z nichž každý bude mít přístup ke všem oddílům v tabulce.

V rámci instance klienta můžete zvýšit propustnost prováděním operací úložiště asynchronně. Klientská knihovna služby Storage usnadňuje psaní asynchronních dotazů a úprav. Můžete například začít synchronní metodou, která načte všechny entity v oddílu, jak je znázorněno v následujícím kódu jazyka C#:

private static void ManyEntitiesQuery(TableClient employeeTable, string department)
{
    TableContinuationToken continuationToken = null;
    do
    {
        var employees = employeeTable.Query<EmployeeEntity>($"PartitionKey eq {department}");
        foreach (var emp in employees.AsPages())
        {
            // ...
            continuationToken = emp.ContinuationToken;
        }
        
    } while (continuationToken != null);
}  

Tento kód můžete snadno upravit tak, aby se dotaz spouštěl asynchronně následujícím způsobem:

private static async Task ManyEntitiesQueryAsync(TableClient employeeTable, string department)
{
    TableContinuationToken continuationToken = null;
    do
    {
        var employees = await employeeTable.QueryAsync<EmployeeEntity>($"PartitionKey eq {department}");
        foreach (var emp in employees.AsPages())
        {
            // ...
            continuationToken = emp.ContinuationToken;
        }

    } while (continuationToken != null);
}  

V tomto asynchronním příkladu uvidíte následující změny z synchronní verze:

  • Podpis metody teď obsahuje modifikátor async a vrátí instanci úlohy .
  • Místo volání metody Query k načtení výsledků teď metoda volá Metodu QueryAsync a používá modifikátor await k asynchronnímu načtení výsledků.

Klientská aplikace může tuto metodu volat vícekrát (s různými hodnotami parametru oddělení ) a každý dotaz se spustí v samostatném vlákně.

Entity můžete také asynchronně vkládat, aktualizovat a odstraňovat. Následující příklad jazyka C# ukazuje jednoduchou synchronní metodu pro vložení nebo nahrazení entity zaměstnance:

private static void SimpleEmployeeUpsert(
    TableClient employeeTable,
    EmployeeEntity employee)
{
    var result = employeeTable.UpdateEntity(employee, Azure.ETag.All, TableUpdateMode.Replace);
    Console.WriteLine("HTTP Status: {0}", result.Status);
}  

Tento kód můžete snadno upravit tak, aby aktualizace běžela asynchronně následujícím způsobem:

private static async Task SimpleEmployeeUpsertAsync(
    TableClient employeeTable,
    EmployeeEntity employee)
{
    var result = await employeeTable.UpdateEntityAsync(employee, Azure.ETag.All, TableUpdateMode.Replace);
    Console.WriteLine("HTTP Status: {0}", result.Result.Status);
}  

V tomto asynchronním příkladu uvidíte následující změny z synchronní verze:

  • Podpis metody teď obsahuje modifikátor async a vrátí instanci úlohy .
  • Místo volání metody Execute k aktualizaci entity metoda nyní volá ExecuteAsync metoda a používá modifikátor await k asynchronnímu načtení výsledků.

Klientská aplikace může volat více asynchronních metod, jako je tato, a každá vyvolání metody se spustí v samostatném vlákně.

Další kroky