Compartir a través de


Columnas generadas por Delta Lake

Importante

Esta característica está en versión preliminar pública.

Delta Lake ahora admite columnas generadas, que son un tipo especial de columna cuyos valores se generan automáticamente según una función especificada por el usuario sobre otras columnas de la tabla Delta. Cuando escribe en una tabla con columnas generadas y no proporciona valores de forma explícita para ellas, Delta Lake calcula automáticamente los valores. Por ejemplo, puede generar automáticamente una columna de fecha (para crear particiones de la tabla por fecha) a partir de la columna de marca de tiempo; cualquier escritura en la tabla solo deberá especificar los datos de la columna de marca de tiempo. Sin embargo, si proporciona explícitamente valores para ellas, estos deben cumplir la restricción (<value> <=> <generation expression>) IS TRUE, ya que de lo contrario no se realizará la escritura y aparecerá el error.

Importante

Las tablas creadas con columnas generadas tienen una versión del protocolo de escritor de tablas superior a la predeterminada. Consulte ¿Cómo administra Azure Databricks la compatibilidad de funciones de Delta Lake? para comprender el versionado de protocolos de tabla y lo que significa tener una versión superior de una versión de protocolo de tabla.

Creación de una tabla con columnas generadas

En el ejemplo siguiente se muestra cómo crear una tabla con columnas generadas:

SQL

CREATE TABLE default.people10m (
  id INT,
  firstName STRING,
  middleName STRING,
  lastName STRING,
  gender STRING,
  birthDate TIMESTAMP,
  dateOfBirth DATE GENERATED ALWAYS AS (CAST(birthDate AS DATE)),
  ssn STRING,
  salary INT
)

Python

DeltaTable.create(spark) \
  .tableName("default.people10m") \
  .addColumn("id", "INT") \
  .addColumn("firstName", "STRING") \
  .addColumn("middleName", "STRING") \
  .addColumn("lastName", "STRING", comment = "surname") \
  .addColumn("gender", "STRING") \
  .addColumn("birthDate", "TIMESTAMP") \
  .addColumn("dateOfBirth", DateType(), generatedAlwaysAs="CAST(birthDate AS DATE)") \
  .addColumn("ssn", "STRING") \
  .addColumn("salary", "INT") \
  .execute()

Scala

DeltaTable.create(spark)
  .tableName("default.people10m")
  .addColumn("id", "INT")
  .addColumn("firstName", "STRING")
  .addColumn("middleName", "STRING")
  .addColumn(
    DeltaTable.columnBuilder("lastName")
      .dataType("STRING")
      .comment("surname")
      .build())
  .addColumn("lastName", "STRING", comment = "surname")
  .addColumn("gender", "STRING")
  .addColumn("birthDate", "TIMESTAMP")
  .addColumn(
    DeltaTable.columnBuilder("dateOfBirth")
     .dataType(DateType)
     .generatedAlwaysAs("CAST(dateOfBirth AS DATE)")
     .build())
  .addColumn("ssn", "STRING")
  .addColumn("salary", "INT")
  .execute()

Las columnas generadas se almacenan como si fueran columnas normales. Es decir, ocupan almacenamiento.

Las restricciones siguientes se aplican a las columnas generadas:

  • Una expresión de generación puede usar cualquier función de SQL en Spark que devuelva siempre el mismo resultado cuando se den los mismos valores de argumento, excepto los siguientes tipos de funciones:
    • Funciones definidas por el usuario.
    • Funciones de agregado.
    • Funciones de ventana.
    • Funciones que devuelven varias filas.

Delta Lake puede generar filtros de partición para una consulta cada vez que una columna de partición se define mediante una de las siguientes expresiones:

Nota:

Photon es necesario en Databricks Runtime 10.4 LTS y versiones anteriores. Photon no es necesario en Databricks Runtime 11.3 LTS y versiones posteriores.

  • CAST(col AS DATE) y el tipo de col es TIMESTAMP.
  • YEAR(col) y el tipo de col es TIMESTAMP.
  • Dos columnas de partición definidas por YEAR(col), MONTH(col) y el tipo de col es TIMESTAMP.
  • Tres columnas de partición definidas por YEAR(col), MONTH(col), DAY(col) y el tipo de col es TIMESTAMP.
  • Cuatro columnas de partición definidas por YEAR(col), MONTH(col), DAY(col), HOUR(col) y el tipo de col es TIMESTAMP.
  • SUBSTRING(col, pos, len) y el tipo de col es STRING
  • DATE_FORMAT(col, format) y el tipo de col es TIMESTAMP.
    • Solo puede utilizar formatos de fecha con los siguientes patrones: yyyy-MM y yyyy-MM-dd-HH.
    • En Databricks Runtime 10.4 LTS y posteriores, también puede utilizar el siguiente patrón: yyyy-MM-dd.

Si una de las expresiones anteriores define una columna de la partición y una consulta filtra los datos mediante la columna base subyacente de una expresión de generación, Delta Lake examina la relación entre la columna base y la columna generada y rellena los filtros de partición en función de los datos de la columna de partición generada, siempre que sea posible. Por ejemplo, si tenemos la siguiente tabla:

CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
eventDate date GENERATED ALWAYS AS (CAST(eventTime AS DATE))
)
PARTITIONED BY (eventType, eventDate)

Si después se ejecuta la siguiente consulta:

SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" <= "2020-10-01 12:00:00"

Delta Lake genera automáticamente un filtro de partición para que la consulta anterior solo lea los datos de la partición date=2020-10-01, incluso si no se especifica ningún filtro de partición.

En este otro ejemplo, tenemos la siguiente tabla:

CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
year INT GENERATED ALWAYS AS (YEAR(eventTime)),
month INT GENERATED ALWAYS AS (MONTH(eventTime)),
day INT GENERATED ALWAYS AS (DAY(eventTime))
)
PARTITIONED BY (eventType, year, month, day)

Si después se ejecuta la siguiente consulta:

SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" <= "2020-10-01 12:00:00"

Delta Lake genera automáticamente un filtro de partición para que la consulta anterior solo lea los datos de la partición year=2020/month=10/day=01, aunque no se especifique ningún filtro de partición.

Puede usar una cláusula EXPLAIN y comprobar el plan proporcionado para ver si Delta Lake genera automáticamente filtros de partición.

Uso de columnas de identidad en Delta Lake

Importante

Declarar una columna de identidad en una tabla Delta deshabilita las transacciones concurrentes. Utilice columnas de identidad únicamente en casos en los que no se requieran escrituras simultáneas en la tabla de destino.

Las columnas de identidad de Delta Lake son un tipo de columna generada que asigna valores únicos para cada registro insertado en una tabla. En el siguiente ejemplo se muestra la sintaxis básica para declarar una columna de identidad durante una instrucción de creación de una tabla:

SQL

CREATE TABLE table_name (
  id_col1 BIGINT GENERATED ALWAYS AS IDENTITY,
  id_col2 BIGINT GENERATED ALWAYS AS IDENTITY (START WITH -1 INCREMENT BY 1),
  id_col3 BIGINT GENERATED BY DEFAULT AS IDENTITY,
  id_col4 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH -1 INCREMENT BY 1)
 )

Python

from delta.tables import DeltaTable, IdentityGenerator
from pyspark.sql.types import LongType

DeltaTable.create()
  .tableName("table_name")
  .addColumn("id_col1", dataType=LongType(), generatedAlwaysAs=IdentityGenerator())
  .addColumn("id_col2", dataType=LongType(), generatedAlwaysAs=IdentityGenerator(start=-1, step=1))
  .addColumn("id_col3", dataType=LongType(), generatedByDefaultAs=IdentityGenerator())
  .addColumn("id_col4", dataType=LongType(), generatedByDefaultAs=IdentityGenerator(start=-1, step=1))
  .execute()

Scala

import io.delta.tables.DeltaTable
import org.apache.spark.sql.types.LongType

DeltaTable.create(spark)
  .tableName("table_name")
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col1")
      .dataType(LongType)
      .generatedAlwaysAsIdentity().build())
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col2")
      .dataType(LongType)
      .generatedAlwaysAsIdentity(start = -1L, step = 1L).build())
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col3")
      .dataType(LongType)
      .generatedByDefaultAsIdentity().build())
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col4")
      .dataType(LongType)
      .generatedByDefaultAsIdentity(start = -1L, step = 1L).build())
  .execute()

Nota:

Las API de Scala y Python para columnas de identidad están disponibles en Databricks Runtime 16.0 y versiones posteriores.

Para ver todas las opciones de sintaxis SQL para crear tablas con columnas de identidad, consulte CREATE TABLE [USING].

Opcionalmente, puede especificar lo siguiente:

  • Un valor inicial.
  • Un tamaño de paso, que puede ser positivo o negativo.

El valor inicial y el tamaño del paso se usan de forma predeterminada en 1. No se puede especificar un tamaño de paso de 0.

Los valores asignados por las columnas de identidad son únicos y se incrementan en la dirección del paso especificado, y en múltiplos del tamaño del paso especificado, pero no se garantiza que sean contiguos. Por ejemplo, con un valor inicial de 0 y un tamaño de paso de 2, todos los valores son números pares positivos, pero es posible que se omitan algunos números pares.

Al usar la cláusula GENERATED BY DEFAULT AS IDENTITY, las operaciones de inserción pueden especificar valores para la columna de identidad. Modifique la cláusula para que sea GENERATED ALWAYS AS IDENTITY para invalidar la capacidad de establecer manualmente los valores.

Las columnas de identidad solo admiten el tipo BIGINT, y las operaciones se cancelan si el valor asignado excede el rango admitido por BIGINT.

Para obtener información sobre la sincronización de valores de columna de identidad con datos, consulte ALTER TABLE ... Cláusula COLUMN.

Columnas de identidad y CTAS

No se pueden definir restricciones de esquema, columna de identidad ni ninguna otra especificación de tabla al usar una instrucción CREATE TABLE table_name AS SELECT (CTAS).

Para crear una nueva tabla con una columna de identidad y rellenarla con datos existentes, haga lo siguiente:

  1. Cree una tabla con el esquema correcto, incluida la definición de columna de identidad y otras propiedades de tabla.
  2. Ejecute una operación INSERT.

En el ejemplo siguiente se usa la palabra clave DEFAULT para definir la columna de identidad. Si los datos insertados en la tabla incluyen valores válidos para la columna de identidad, se usan estos valores.

CREATE OR REPLACE TABLE new_table (
  id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 5),
  event_date DATE,
  some_value BIGINT
);

-- Inserts records including existing IDs
INSERT INTO new_table
SELECT id, event_date, some_value FROM old_table;

-- Insert records and generate new IDs
INSERT INTO new_table
SELECT event_date, some_value FROM new_records;

Limitaciones de columna de identidad

Existen las siguientes limitaciones al trabajar con columnas de identidad:

  • Las tablas con columnas de identidad habilitadas no permiten transacciones simultáneas.
  • No se puede particionar una tabla por una columna de identidad.
  • No se puede usar ALTER TABLE para ADD, REPLACE o CHANGE una columna de identidad.
  • No se puede actualizar el valor de una columna de identidad para un registro existente.

Nota:

Para cambiar el valor de IDENTITY para un registro existente, debe eliminar el registro y INSERT como un nuevo registro.