Condividi tramite


Cursori del database

Si applica a: ✅esplora dati di Azure

Un cursore di database è un oggetto a livello di database che consente di eseguire più volte query su un database. Si ottengono risultati coerenti anche se sono presenti data-append o data-retention operazioni in parallelo con le query.

I cursori di database sono progettati per gestire due scenari importanti:

  • Possibilità di ripetere più volte la stessa query e ottenere gli stessi risultati, purché la query indichi "stesso set di dati".

  • Possibilità di eseguire una query "esattamente una volta". Questa query "vede" solo i dati non visualizzati da una query precedente, perché i dati non erano quindi disponibili. La query consente, ad esempio, di eseguire l'iterazione di tutti i dati appena arrivati in una tabella senza timore di elaborare lo stesso record due volte o ignorare i record per errore.

Il cursore del database è rappresentato nel linguaggio di query come valore scalare di tipo string. Il valore effettivo deve essere considerato opaco e non esiste alcun supporto per alcuna operazione diversa da salvare il valore o usare le funzioni di cursore seguenti.

Funzioni cursori

Kusto offre tre funzioni per implementare i due scenari precedenti:

  • cursor_current(): usare questa funzione per recuperare il valore corrente del cursore del database. È possibile usare questo valore come argomento per le altre due funzioni.

  • cursor_after(rhs:string): questa funzione speciale può essere usata nei record di tabella con criterio IngestionTime abilitato. Restituisce un valore scalare di tipo bool che indica se il valore del cursore del database ingestion_time() del record è successivo al valore del cursore del database rhs.

  • cursor_before_or_at(rhs:string): questa funzione speciale può essere usata nei record di tabella con i criteri IngestionTime abilitati. Restituisce un valore scalare di tipo bool che indica se il valore del cursore del database ingestion_time() del record è precedente o al valore del cursore del database rhs.

Le due funzioni speciali (cursor_after e cursor_before_or_at) hanno anche un effetto collaterale: quando vengono usate, Kusto genera il valore corrente del cursore del database al set di risultati @ExtendedProperties della query. Il nome della proprietà per il cursore è Cursore il relativo valore è un singolo string.

Per esempio:

{"Cursor" : "636040929866477946"}

Restrizioni

I cursori di database possono essere usati solo con le tabelle per le quali è abilitato il criterio IngestionTime. Ogni record in una tabella di questo tipo è associato al valore del cursore del database in vigore al momento dell'inserimento del record. Di conseguenza, è possibile usare la funzione ingestion_time().

L'oggetto cursore del database non contiene alcun valore significativo, a meno che il database non disponga di almeno una tabella con un criterio IngestionTime definito. Questo valore viene garantito di aggiornare, in base alle esigenze della cronologia di inserimento, in tali tabelle e le query eseguite, che fanno riferimento a tali tabelle. Potrebbe, o no, essere aggiornato in altri casi.

Il processo di inserimento esegue prima il commit dei dati, in modo che sia disponibile per l'esecuzione di query e quindi assegna solo un valore di cursore effettivo a ogni record. L'esecuzione di query sui dati immediatamente dopo l'inserimento tramite un cursore di database potrebbe non incorporare gli ultimi record aggiunti perché il valore del cursore non è ancora stato assegnato. Inoltre, il recupero ripetuto del valore del cursore del database corrente potrebbe restituire lo stesso valore, anche se l'inserimento è stato eseguito tra di loro, perché solo un commit del cursore può aggiornarne il valore.

L'esecuzione di query su una tabella basata su cursori di database è garantita solo per il "lavoro" (fornendo garanzie di tipo exactly-once) se i record vengono inseriti direttamente in tale tabella. Se si usano comandi extent, ad esempio extent con estensione move o .replace extents per spostare i dati nella tabella oppure se si usa tabella .rename, l'esecuzione di query su questa tabella tramite cursori di database non garantisce la mancanza di dati. Ciò è dovuto al fatto che il tempo di inserimento dei record viene assegnato all'inserimento iniziale e non cambia durante l'operazione di spostamento extent.

Quando gli extent vengono spostati nella tabella di destinazione, il valore del cursore assegnato potrebbe essere già stato elaborato e la query successiva eseguita dal cursore del database perderà i nuovi record.

Esempio: Elaborazione di record esattamente una volta

Per una tabella Employees con schema [Name, Salary], per elaborare continuamente nuovi record durante l'inserimento nella tabella, usare il processo seguente:

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