Cursores da base de dados
Aplica-se a: ✅Azure Data Explorer
Um cursor de banco de dados é um objeto no nível de banco de dados que permite consultar um banco de dados várias vezes. Você obtém resultados consistentes mesmo se houver data-append
ou data-retention
operações acontecendo 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". Esta consulta apenas "vê" os dados que uma consulta anterior não viu, porque os dados não estavam disponíveis na altura. A consulta permite que você itere, por exemplo, através de todos os dados recém-chegados em uma tabela sem medo de processar o mesmo registro duas vezes ou pular registros por engano.
O cursor do 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 além de salvar seu valor ou usar as seguintes funções de cursor.
Funções do cursor
Kusto fornece três funções para ajudar a implementar os dois cenários acima:
cursor_current(): Use esta função para recuperar o valor atual do cursor do banco de dados. Você pode usar esse valor como um argumento para as duas outras funções.
cursor_after(rhs:string): Esta função especial pode ser usada em registros de tabela que tenham a política IngestionTime habilitada. Ele retorna um valor escalar do tipo
bool
indicando se o valor do cursor do banco de dadosingestion_time()
do registro vem após o valor do cursor do banco de dadosrhs
.cursor_before_or_at(rhs:string): Esta 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 do 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, Kusto emite o valor atual do cursor do 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 o de política
O objeto cursor do 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. Este valor é garantido para atualizar, conforme necessário pelo histórico de ingestão, em tais tabelas e as consultas executadas, que fazem referência a tais tabelas. Poderia, ou não, ser atualizado noutros casos.
O processo de ingestão primeiro confirma os dados, para que fiquem disponíveis para consulta, e só então atribui um valor real do cursor 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 do banco de dados repetidamente pode retornar o mesmo valor, mesmo que a ingestão tenha sido feita no meio, porque apenas uma confirmação do cursor pode atualizar seu valor.
Consultar uma tabela com base em cursores de banco de dados só é garantido para "funcionar" (fornecendo garantias exatamente uma vez) se os registros forem ingeridos diretamente nessa tabela. Se você usar comandos extensions, como .move extents ou .replace extents para mover dados para a tabela, ou se estiver usando tabela .rename, não é garantido consultar esta tabela usando cursores de banco de dados para evitar a falta de dados. Isso ocorre porque o tempo de ingestão dos registros é atribuído quando ingerido inicialmente e não muda durante a operação de extensões de movimento.
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 do banco de dados perderá os novos registros.
Exemplo: Processar registos exatamente uma vez
Para uma tabela Employees
com esquema [Name, Salary]
, para processar continuamente novos registros à medida que 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