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 que haja operações de data-append
ou data-retention
em paralelo com as consultas.
Os cursores de banco de dados são 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 "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 qualquer operação que não seja salvar seu valor ou usar as seguintes funções de cursor.
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
indicando se o valor do cursor de banco de dadosingestion_time()
do registro vem após o valor do cursor do banco de dadosrhs
.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
indicando se o valor do cursor de banco de dadosingestion_time()
do registro vem antes ou no valor do cursor do banco de dadosrhs
.
As duas funções especiais (cursor_after
e cursor_before_or_at
) também têm um efeito colateral: quando são usadas, o Kusto emite o valor atual do cursor de banco de dados para o conjunto de resultados @ExtendedProperties
da consulta. O nome da propriedade do cursor é Cursor
e 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 está 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
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 primeiro confirma os dados, de modo que eles estão disponíveis para consulta e, somente em seguida, atribui um valor de cursor real a cada registro. Consultar dados imediatamente após a ingestão usando um cursor de banco de dados pode não incorporar os últimos registros adicionados porque o valor do cursor ainda não foi atribuído. Além disso, recuperar o valor atual do cursor de banco de dados repetidamente pode retornar o mesmo valor, mesmo que a ingestão tenha sido feita no meio, porque 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ê usar comandos de extensões, como .move extents ou .replace extents para mover dados para a tabela ou se você estiver usando .rename table, então consultar essa tabela usando cursores de banco de dados não é garantido para evitar a falta de dados. 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.
Quando as extensões são movidas para a tabela de destino, o valor do cursor atribuído pode já ter sido processado e a próxima consulta pelo cursor de banco de dados perderá os novos registros.
Exemplo: processamento de registros exatamente uma vez
Para uma tabela Employees
com [Name, Salary]
de esquema, para processar continuamente novos registros à medida que 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
Conteúdo relacionado
- cursor_current()
- cursor_before_or_at()
- cursor_after()
- de política
IngestionTime