Compartir vía


Cursores de base de datos

Un cursor de base de datos es un objeto de nivel de base de datos que permite consultar una base de datos varias veces. Obtiene resultados coherentes incluso si hay data-append operaciones o data-retention que se producen en paralelo con las consultas.

Los cursores de base de datos están diseñados para abordar dos escenarios importantes:

  • La capacidad de repetir la misma consulta varias veces y obtener los mismos resultados, siempre que la consulta indique "mismo conjunto de datos".

  • La capacidad de realizar una consulta "exactamente una vez". Esta consulta solo "ve" los datos que no vio una consulta anterior, ya que los datos no están disponibles entonces. La consulta permite recorrer en iteración, por ejemplo, todos los datos recién llegados de una tabla sin miedo a procesar el mismo registro dos veces o omitir los registros por error.

El cursor de base de datos se representa en el lenguaje de consulta como un valor escalar de tipo string. El valor real debe considerarse opaco y no hay compatibilidad con ninguna operación que no sea guardar su valor o usar las funciones de cursor que se indican a continuación.

Funciones de cursores

Kusto proporciona tres funciones para ayudar a implementar los dos escenarios anteriores:

  • cursor_current(): use esta función para recuperar el valor actual del cursor de base de datos. Puede usar este valor como argumento para las otras dos funciones.

  • cursor_after(rhs:string): esta función especial se puede usar en los registros de tabla que tienen habilitada la directiva IngestionTime . Devuelve un valor escalar de tipo bool que indica si el valor del cursor de la base de datos del ingestion_time() registro viene después del valor del rhs cursor de la base de datos.

  • cursor_before_or_at(rhs:string): esta función especial se puede usar en los registros de tabla que tienen habilitada la directiva IngestionTime . Devuelve un valor escalar de tipo bool que indica si el valor del cursor de base de datos del ingestion_time() registro viene antes o en el valor del rhs cursor de base de datos.

Las dos funciones especiales (cursor_after y cursor_before_or_at) también tienen un efecto secundario: cuando se usan, Kusto emitirá el valor actual del cursor de base de datos al @ExtendedProperties conjunto de resultados de la consulta. El nombre de propiedad del cursor es Cursory su valor es un único string.

Por ejemplo:

{"Cursor" : "636040929866477946"}

Restricciones

Los cursores de base de datos solo se pueden usar con tablas para las que se ha habilitado la directiva IngestionTime . Cada registro de esta tabla está asociado al valor del cursor de base de datos que estaba en vigor cuando se ingerió el registro. Por lo tanto, se puede usar la función ingestion_time().

El objeto de cursor de base de datos no contiene ningún valor significativo a menos que la base de datos tenga al menos una tabla que tenga definida una directiva IngestionTime . Se garantiza que este valor se actualice, según sea necesario, en el historial de ingesta, en estas tablas y las consultas ejecutadas, que hacen referencia a dichas tablas. Es posible que, o no, se actualice en otros casos.

El proceso de ingesta confirma primero los datos, de modo que esté disponible para realizar consultas y, a continuación, solo asigna un valor de cursor real a cada registro. Si intenta consultar los datos inmediatamente después de la finalización de la ingesta mediante un cursor de base de datos, es posible que los resultados aún no incorporen los últimos registros agregados, ya que aún no se les ha asignado el valor del cursor. Además, la recuperación del valor actual del cursor de base de datos puede devolver repetidamente el mismo valor, incluso si la ingesta se realizó entre sí, ya que solo una confirmación del cursor puede actualizar su valor.

La consulta de una tabla basada en cursores de base de datos solo se garantiza que "funcione" (proporcionando garantías exactamente una vez) si los registros se ingieren directamente en esa tabla. Si usa comandos de extensiones, como mover extensiones.replace/extensiones para mover datos a la tabla, o si usa .rename table, no se garantiza que la consulta de esta tabla mediante cursores de base de datos no pierda datos. Esto se debe a que el tiempo de ingesta de los registros se asigna al ingerir inicialmente y no cambia durante la operación de extensión de movimiento. Por lo tanto, cuando las extensiones se mueven a la tabla de destino, es posible que el valor del cursor asignado a los registros de estas extensiones ya se haya procesado (y la siguiente consulta por cursor de base de datos perderá los nuevos registros).

Ejemplo: Procesamiento de registros exactamente una vez

Para una tabla Employees con esquema [Name, Salary], para procesar continuamente nuevos registros a medida que se ingieren en la tabla, use el siguiente proceso:

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