Cursores de banco de dados

Um cursor de banco de dados é um objeto no nível do banco de dados que permite consultar um banco de dados várias vezes. Você obtém resultados consistentes mesmo se houver data-append operações ou data-retention ocorrendo em paralelo com as consultas.

Os cursores de banco de dados foram projetados 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". Essa consulta apenas "vê" os dados que uma consulta anterior não viu, porque os dados não estão disponíveis na época. A consulta permite iterar, por exemplo, todos os dados recém-chegados em uma tabela sem medo de processar o mesmo registro duas vezes ou ignorar registros por engano.

O cursor de banco de dados é representado na linguagem de consulta como um valor escalar do tipo string. O valor real deve ser considerado opaco e não há suporte para nenhuma operação diferente de salvar seu valor ou usar as funções de cursor indicadas abaixo.

Funções de cursor

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

  • cursor_current(): use essa função para recuperar o valor atual do cursor de banco de dados. Você pode usar esse valor como um argumento para as duas outras funções.

  • cursor_after(rhs:string): essa função especial pode ser usada em registros de tabela que têm a política IngestionTime habilitada. Ele retorna um valor escalar do tipo bool que indica se o valor do cursor de banco de dados do ingestion_time() registro vem após o valor do cursor do rhs banco de dados.

  • cursor_before_or_at(rhs:string): essa função especial pode ser usada nos registros de tabela que têm a política IngestionTime habilitada. Ele retorna um valor escalar do tipo bool que indica se o valor do cursor de banco de dados do ingestion_time() registro vem antes ou no valor do cursor do rhs banco de dados.

As duas funções especiais (cursor_after e cursor_before_or_at) também têm um efeito colateral: quando forem usadas, o Kusto emitirá o valor atual do cursor de banco de dados para o @ExtendedProperties conjunto de resultados da consulta. O nome da propriedade do cursor é Cursore seu valor é um único string.

Por exemplo:

{"Cursor" : "636040929866477946"}

Restrições

Os cursores de banco de dados só podem ser usados com tabelas para as quais a política IngestionTime foi habilitada. Cada registro em tal tabela é associado ao valor do cursor de banco de dados que estava em vigor quando o registro foi ingerido. Dessa forma, a função ingestion_time() pode ser usada.

O objeto de cursor de banco de dados não contém nenhum valor significativo, a menos que o banco de dados tenha pelo menos uma tabela que tenha uma política IngestionTime definida. Esse valor é garantido para atualizar, conforme necessário pelo histórico de ingestão, em tais tabelas e nas consultas executadas, que fazem referência a essas tabelas. Ele pode ou não ser atualizado em outros casos.

O processo de ingestão confirma primeiro os dados, de modo que eles estão disponíveis para consulta e, em seguida, atribui um valor de cursor real a cada registro. Se você tentar consultar dados imediatamente após a conclusão da ingestão usando um cursor de banco de dados, os resultados podem ainda não incorporar os últimos registros adicionados, pois ainda não foram atribuídos o valor do cursor. Além disso, recuperar o valor do cursor de banco de dados atual repetidamente pode retornar o mesmo valor, mesmo que a ingestão tenha sido feita no meio, pois apenas uma confirmação de cursor pode atualizar seu valor.

Consultar uma tabela com base em cursores de banco de dados só é garantido para "trabalhar" (fornecendo garantias exatamente uma vez) se os registros forem ingeridos diretamente nessa tabela. Se você estiver usando comandos de extensões, como extensões/ de movimentação.extensões de substituição para mover dados para a tabela ou se estiver usando a tabela .rename, não é garantido que a consulta a essa tabela usando cursores de banco de dados não perca nenhum dado. Isso ocorre porque o tempo de ingestão dos registros é atribuído quando inicialmente ingerido e não é alterado durante a operação de extensões de movimentação. Portanto, quando as extensões são movidas para a tabela de destino, é possível que o valor do cursor atribuído aos registros nessas extensões já tenha sido processado (e a próxima consulta pelo cursor de banco de dados perderá os novos registros).

Exemplo: processando registros exatamente uma vez

Para uma tabela Employees com esquema [Name, Salary], para processar continuamente novos registros conforme eles são ingeridos na tabela, use 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