Kurzory databází

Kurzor databáze je objekt na úrovni databáze, který umožňuje dotazovat databázi vícekrát. Konzistentní výsledky získáte i v případě, že data-append paralelně s dotazy probíhají nějaké operace.data-retention

Kurzory databáze jsou navržené tak, aby řešily dva důležité scénáře:

  • Možnost opakovat stejný dotaz několikrát a získat stejné výsledky, pokud dotaz označuje "stejnou sadu dat".

  • Možnost vytvořit dotaz "přesně jednou". Tento dotaz "vidí" pouze data, která předchozí dotaz neviděl, protože data nebyla v té chvíli k dispozici. Dotaz umožňuje například iterovat všechna nově příchozí data v tabulce, aniž byste se museli obávat, že stejný záznam zpracujete dvakrát nebo záznamy omylem přeskočíte.

Kurzor databáze je v dotazovacím jazyce reprezentován jako skalární hodnota typu string. Skutečná hodnota by měla být považována za neprůsložnou a neexistuje žádná jiná podpora pro žádnou operaci, než uložení její hodnoty nebo použití funkcí kurzoru, které jsou uvedené níže.

Kurzorové funkce

Kusto nabízí tři funkce, které vám pomůžou implementovat dva výše uvedené scénáře:

  • cursor_current(): Pomocí této funkce můžete načíst aktuální hodnotu kurzoru databáze. Tuto hodnotu můžete použít jako argument pro dvě další funkce.

  • cursor_after(rhs:string): Tuto speciální funkci je možné použít u záznamů tabulky, které mají povolenou zásadu IngestionTime . Vrátí skalární hodnotu typu bool označující, jestli hodnota kurzoru databáze záznamu ingestion_time() následuje po hodnotě kurzoru rhs databáze.

  • cursor_before_or_at(rhs:string): Tuto speciální funkci je možné použít u záznamů tabulky, které mají povolenou zásadu IngestionTime . Vrátí skalární hodnotu typu bool označující, jestli je hodnota databázového ingestion_time() kurzoru záznamu před nebo na hodnotu kurzoru rhs databáze.

Dvě speciální funkce (cursor_after a cursor_before_or_at) mají také vedlejší účinek: Při jejich použití Kusto vygeneruje aktuální hodnotu kurzoru databáze do @ExtendedProperties sady výsledků dotazu. Název vlastnosti kurzoru je Cursora jeho hodnota je jedna string.

Příklad:

{"Cursor" : "636040929866477946"}

Omezení

Kurzory databáze se dají použít jenom s tabulkami, pro které jsou povolené zásady IngestionTime . Každý záznam v takové tabulce je přidružený k hodnotě kurzoru databáze, která byla v platnosti při ingestování záznamu. Proto je možné použít funkci ingestion_time().

Objekt kurzoru databáze nemá žádnou smysluplnou hodnotu, pokud databáze neobsahuje alespoň jednu tabulku s definovanou zásadou IngestionTime . Tato hodnota zaručuje, že se podle potřeby historie příjmu dat aktualizuje do takových tabulek a spuštěných dotazů, které na tyto tabulky odkazují. V jiných případech se může nebo nemusí aktualizovat.

Proces příjmu dat nejprve potvrdí data, aby byla k dispozici pro dotazování, a teprve pak každému záznamu přiřadí skutečnou hodnotu kurzoru. Pokud se pokusíte dotazovat na data bezprostředně po dokončení příjmu dat pomocí kurzoru databáze, je možné, že výsledky ještě nezačlení poslední přidané záznamy, protože ještě nemají přiřazenou hodnotu kurzoru. Opakované načtení aktuální hodnoty kurzoru databáze může také vrátit stejnou hodnotu, i když byl příjem dat proveden mezi tím, protože pouze potvrzení kurzoru může aktualizovat jeho hodnotu.

Dotazování tabulky založené na kurzorech databáze je zaručeno, že "funguje" (poskytuje záruky přesně jednou), pouze pokud jsou záznamy ingestovány přímo do této tabulky. Pokud k přesunu dat do tabulky používáte příkazy pro rozsahy, například move extents.replace/extents, nebo pokud používáte .rename table, pak při dotazování této tabulky pomocí kurzorů databáze není zaručeno, že vám neuniknou žádná data. Důvodem je to, že čas příjmu dat záznamů se přiřadí při počátečním ingestování a během operace rozsahů přesunu se nemění. Proto když se rozsahy přesunou do cílové tabulky, je možné, že hodnota kurzoru přiřazená záznamům v těchto rozsahech už byla zpracována (a další dotaz kurzorem databáze nové záznamy vynechá).

Příklad: Zpracování záznamů přesně jednou

Pokud chcete v tabulce Employees se schématem [Name, Salary]průběžně zpracovávat nové záznamy při jejich ingestování do tabulky, použijte následující postup:

// [Once] Enable the IngestionTime policy on table Employees
.set table Employees policy ingestiontime true

// [Once] Get all the data that the Employees table currently holds 
Employees | where cursor_after('')

// The query above will return the database cursor value in
// the @ExtendedProperties result set. Lets assume that it returns
// the value '636040929866477946'

// [Many] Get all the data that was added to the Employees table
// since the previous query was run using the previously-returned
// database cursor 
Employees | where cursor_after('636040929866477946') // -> 636040929866477950

Employees | where cursor_after('636040929866477950') // -> 636040929866479999

Employees | where cursor_after('636040929866479999') // -> 636040939866479000