Kursory bazy danych

Kursor bazy danych jest obiektem na poziomie bazy danych, który umożliwia wielokrotne wykonywanie zapytań dotyczących bazy danych. Uzyskujesz spójne wyniki nawet wtedy, gdy występują data-append operacje lub data-retention występują równolegle z zapytaniami.

Kursory bazy danych są przeznaczone do rozwiązywania dwóch ważnych scenariuszy:

  • Możliwość wielokrotnego powtarzania tego samego zapytania i uzyskiwania tych samych wyników, o ile zapytanie wskazuje "ten sam zestaw danych".

  • Możliwość utworzenia zapytania "dokładnie raz". To zapytanie "widzi" tylko dane, których poprzednie zapytanie nie widziało, ponieważ dane nie były wówczas dostępne. Zapytanie umożliwia na przykład iterowanie wszystkich nowo przybyłych danych w tabeli bez obawy o przetwarzanie tego samego rekordu dwa razy lub pomijanie rekordów przez pomyłkę.

Kursor bazy danych jest reprezentowany w języku zapytań jako wartość skalarna typu string. Wartość rzeczywista powinna być uważana za nieprzezroczystą i nie ma obsługi żadnej operacji innej niż zapisanie jej wartości lub użycie funkcji kursora zanotowane poniżej.

Funkcje kursora

Usługa Kusto udostępnia trzy funkcje ułatwiające zaimplementowanie dwóch powyższych scenariuszy:

  • cursor_current(): użyj tej funkcji, aby pobrać bieżącą wartość kursora bazy danych. Możesz użyć tej wartości jako argumentu do dwóch innych funkcji.

  • cursor_after(rhs:string): Tej specjalnej funkcji można używać w rekordach tabeli z włączonymi zasadami IngestionTime . Zwraca wartość skalarną typu bool wskazującą, czy wartość kursora bazy danych rekordu pochodzi po wartości kursora ingestion_time()rhs bazy danych.

  • cursor_before_or_at(rhs:string): Tej specjalnej funkcji można używać w rekordach tabeli z włączonymi zasadami IngestionTime . Zwraca wartość skalarną typu bool wskazującą, czy wartość kursora bazy danych rekordu ingestion_time() przypada przed, czy na wartość kursora rhs bazy danych.

Dwie specjalne funkcje (cursor_after i cursor_before_or_at) mają również efekt uboczny: Gdy są używane, usługa Kusto emituje bieżącą wartość kursora bazy danych do @ExtendedProperties zestawu wyników zapytania. Nazwa właściwości kursora to Cursor, a jej wartość to pojedynczy stringelement .

Na przykład:

{"Cursor" : "636040929866477946"}

Ograniczenia

Kursory bazy danych mogą być używane tylko z tabelami, dla których włączono zasady IngestionTime . Każdy rekord w takiej tabeli jest skojarzony z wartością kursora bazy danych, który obowiązywał podczas pozyskiwania rekordu. W związku z tym można użyć funkcji ingestion_time( ).

Obiekt kursora bazy danych nie zawiera znaczącej wartości, chyba że baza danych ma co najmniej jedną tabelę, która ma zdefiniowaną zasadę IngestionTime . Ta wartość jest gwarantowana do zaktualizowania, zgodnie z potrzebami historii pozyskiwania, do takich tabel i uruchomionych zapytań, które odwołują się do takich tabel. Może być aktualizowany w innych przypadkach lub nie.

Proces pozyskiwania najpierw zatwierdza dane, tak aby był dostępny do wykonywania zapytań, a następnie przypisuje rzeczywistą wartość kursora do każdego rekordu. Jeśli spróbujesz wykonać zapytanie o dane bezpośrednio po zakończeniu pozyskiwania przy użyciu kursora bazy danych, wyniki mogą jeszcze nie zawierać dodanych ostatnio rekordów, ponieważ nie zostały jeszcze przypisane wartości kursora. Ponadto pobieranie bieżącej wartości kursora bazy danych może wielokrotnie zwracać tę samą wartość, nawet jeśli pozyskiwanie zostało wykonane między, ponieważ tylko zatwierdzenie kursora może zaktualizować jego wartość.

Wykonywanie zapytań względem tabeli na podstawie kursorów bazy danych gwarantuje jedynie "pracę" (zapewniając dokładnie jednokrotne gwarancje), jeśli rekordy są pozyskiwane bezpośrednio do tej tabeli. Jeśli używasz poleceń zakresów, takich jak move extents.replace/extents w celu przeniesienia danych do tabeli lub jeśli używasz polecenia .rename table, wykonywanie zapytań względem tej tabeli przy użyciu kursorów bazy danych nie gwarantuje pominięcia żadnych danych. Wynika to z tego, że czas pozyskiwania rekordów jest przypisywany podczas początkowego pozyskiwania i nie zmienia się podczas operacji przenoszenia zakresów. W związku z tym po przeniesieniu zakresów do tabeli docelowej możliwe jest, że wartość kursora przypisana do rekordów w tych zakresach została już przetworzona (a następne zapytanie przez kursor bazy danych przegapi nowe rekordy).

Przykład: przetwarzanie rekordów dokładnie raz

W przypadku tabeli Employees ze schematem [Name, Salary]użyj następującego procesu, aby stale przetwarzać nowe rekordy podczas pozyskiwania ich do tabeli:

// [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