Cursores de base de dados

Um cursor de base de dados é um objeto ao nível da base de dados que lhe permite consultar uma base de dados várias vezes. Obtém resultados consistentes, mesmo que existam data-append operações em data-retention paralelo com as consultas.

Os cursores de base de dados foram concebidos para abordar dois cenários importantes:

  • A capacidade de repetir a mesma consulta várias vezes e obter os mesmos resultados, desde que a consulta indique "o mesmo conjunto de dados".

  • A capacidade de fazer uma consulta "exatamente uma vez". Esta consulta apenas "vê" os dados que uma consulta anterior não viu, uma vez que os dados não se encontram disponíveis nessa altura. A consulta permite iterar, por exemplo, todos os dados recém-chegados numa tabela sem receio de processar o mesmo registo duas vezes ou de ignorar registos por engano.

O cursor da base de dados é representado na linguagem de consulta como um valor escalar do tipo string. O valor real deve ser considerado opaco e não existe suporte para qualquer operação que não seja guardar o respetivo valor ou utilizar as funções de cursor indicadas abaixo.

Funções do cursor

O Kusto fornece três funções para ajudar a implementar os dois cenários acima:

  • cursor_current(): utilize esta função para obter o valor atual do cursor da base de dados. Pode utilizar este valor como um argumento para as outras duas funções.

  • cursor_after(rhs:string): esta função especial pode ser utilizada em registos de tabela que tenham a política IngestionTime ativada. Devolve um valor escalar do tipo bool que indica se o valor do cursor da base de dados do ingestion_time() registo vem a seguir ao valor do cursor da rhs base de dados.

  • cursor_before_or_at(rhs:string): esta função especial pode ser utilizada nos registos de tabela que têm a política IngestionTime ativada. Devolve um valor escalar do tipo bool que indica se o valor do cursor de base de dados do ingestion_time() registo é apresentado antes ou no valor do cursor da rhs base de dados.

As duas funções especiais (cursor_after e ) também têm um efeito colateral: quando são utilizadas, o Kusto emitirá o valor atual do cursor da base de dados para o @ExtendedProperties conjunto de resultados da cursor_before_or_atconsulta. O nome da propriedade do cursor é Cursor, e o respetivo valor é um único string.

Por exemplo:

{"Cursor" : "636040929866477946"}

Restrições

Os cursores de base de dados só podem ser utilizados com tabelas para as quais a política IngestionTime foi ativada. Cada registo dessa tabela está associado ao valor do cursor da base de dados que estava em vigor quando o registo foi ingerido. Como tal, a função ingestion_time() pode ser utilizada.

O objeto do cursor de base de dados não contém nenhum valor significativo, a menos que a base de dados tenha, pelo menos, uma tabela que tenha uma política IngestionTime definida. Este valor é garantido para atualizar, conforme necessário pelo histórico de ingestão, para essas tabelas e as consultas executadas, que referenciam essas tabelas. Pode, ou não, ser atualizado noutros casos.

Primeiro, o processo de ingestão consolida os dados, para que estejam disponíveis para consulta e, em seguida, atribua apenas um valor de cursor real a cada registo. Se tentar consultar dados imediatamente após a conclusão da ingestão com um cursor de base de dados, os resultados poderão ainda não incorporar os últimos registos adicionados, uma vez que ainda não lhes foi atribuído o valor do cursor. Além disso, obter o valor do cursor de base de dados atual repetidamente pode devolver o mesmo valor, mesmo que a ingestão tenha sido feita pelo meio, porque apenas uma consolidação de cursor pode atualizar o respetivo valor.

Consultar uma tabela com base nos cursores de base de dados só é garantido que "funciona" (fornecendo garantias exatamente uma vez) se os registos forem ingeridos diretamente nessa tabela. Se estiver a utilizar comandos de extensões, como extensões/ de movimentação.substituir extensões para mover dados para a tabela ou se estiver a utilizar a tabela .rename, não é garantido que consultar esta tabela com cursores de base de dados não perca dados. Isto deve-se ao facto de o tempo de ingestão dos registos ser atribuído quando inicialmente ingerido e não ser alterado durante a operação de extensões de movimentação. Por conseguinte, quando as extensões são movidas para a tabela de destino, é possível que o valor do cursor atribuído aos registos nestas extensões já tenha sido processado (e a próxima consulta pelo cursor da base de dados perderá os novos registos).

Exemplo: Processar registos exatamente uma vez

Para uma tabela Employees com esquema [Name, Salary], para processar continuamente novos registos à medida que são ingeridos na tabela, utilize o seguinte processo:

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