Генерируемые столбцы Delta Lake

Внимание

Эта функция предоставляется в режиме общедоступной предварительной версии.

Delta Lake поддерживает созданные столбцы, которые являются особым типом столбца, значения которых автоматически создаются на основе указанной пользователем функции над другими столбцами в таблице Delta. При записи в таблицу с генерируемыми столбцами, если вы не предоставляете значения для них явно, Delta Lake автоматически вычисляет эти значения. Например, можно автоматически создать столбец даты (для секционирования таблицы по дате) из столбца метки времени; все записи в таблицу должны указывать только данные для столбца метки времени. Однако если вы явно предоставляете значения для них, значения должны соответствовать ограничению (<value> <=> <generation expression>) IS TRUE или запись завершится ошибкой.

Внимание

Таблицы, созданные с созданными столбцами, имеют более высокую версию протокола записи таблиц, чем по умолчанию. Ознакомьтесь с совместимостью функций Delta Lake и протоколами , чтобы понять управление версиями протоколов таблиц и то, что значит иметь более высокую версию версии протокола таблицы.

Создание таблицы с созданными столбцами

В следующем примере показано, как создать таблицу с созданными столбцами:

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
)

Питон

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()

Созданные столбцы хранятся так же, как если бы они были обычными столбцами. То есть они занимают место в хранилище.

Следующие ограничения применяются к созданным столбцам:

  • Выражение поколения может использовать любые функции SQL в Spark, которые всегда возвращают тот же результат при указании одинаковых значений аргументов, за исключением следующих типов функций:
    • Определяемые пользователем функции.
    • Агрегатные функции.
    • Функции окна.
    • Функции, возвращающие несколько строк.

Delta Lake может создавать фильтры секций для запроса всякий раз, когда столбец секции определяется одним из следующих выражений:

Примечание.

Фотон требуется в Databricks Runtime 10.4 LTS и ниже. Фотон не требуется в Databricks Runtime 11.3 LTS и более поздних версиях.

  • CAST(col AS DATE) и тип col — TIMESTAMP.
  • YEAR(col) и тип col — TIMESTAMP.
  • Два столбца секции определяются YEAR(col), MONTH(col) и col, а тип col — это .
  • Три столбца секции, определяемые при помощи YEAR(col), MONTH(col), DAY(col), а тип colTIMESTAMP.
  • Четыре столбца раздела, определенные YEAR(col), MONTH(col), DAY(col), HOUR(col), и тип colTIMESTAMP.
  • SUBSTRING(col, pos, len) и тип col — STRING.
  • DATE_FORMAT(col, format) и тип col — TIMESTAMP.
    • Форматы дат можно использовать только со следующими шаблонами: yyyy-MM и yyyy-MM-dd-HH.
    • В Databricks Runtime 10.4 LTS и более поздних версиях можно также использовать следующий шаблон: yyyy-MM-dd

Если столбец секции определяется одним из предыдущих выражений, и запрос фильтрует данные с использованием базового столбца генерационного выражения, Delta Lake анализирует связь между базовым и созданным столбцами и, если возможно, применяет фильтры секций, основанные на созданном столбце секции. Например, учитывая следующую таблицу:

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

Если вы затем выполните следующий запрос:

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

Delta Lake автоматически создает фильтр секций, чтобы предыдущий запрос только считывал данные в разделе date=2020-10-01 даже если фильтр секции не указан.

В качестве другого примера: следующая таблица.

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)

Если вы затем выполните следующий запрос:

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

Delta Lake автоматически создает фильтр секций, чтобы предыдущий запрос только считывал данные в разделе year=2020/month=10/day=01 даже если фильтр секции не указан.

Вы можете использовать предложение EXPLAIN и проверить предоставленный план, чтобы узнать, создаёт ли Delta Lake автоматически какие-либо фильтры разделов.

Использование столбцов идентичности в Delta Lake

Внимание

Объявление столбца идентификаторов в таблице Delta отключает выполнение одновременных транзакций. Используйте только идентификационные столбцы в случаях, когда одновременные записи в целевую таблицу не нужны.

Идентификационные столбцы Delta Lake — это тип сгенерированного столбца, который назначает уникальные значения для каждой записи, вставленной в таблицу. В следующем примере показан базовый синтаксис для объявления столбца идентификатора в инструкции создания таблицы.

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)
 )

Питон

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()

Примечание.

API Scala и Python для идентичных столбцов доступны в Databricks Runtime 16.0 и выше.

Чтобы просмотреть все параметры синтаксиса SQL для создания таблиц со столбцами идентификаторов, см. CREATE TABLE[USING].

При необходимости можно указать следующее:

  • Начальное значение.
  • Размер шага, который может быть положительным или отрицательным.

Начальное значение и размер шага по умолчанию 1. Невозможно указать размер шага 0.

Значения, назначенные identity-столбцами, являются уникальными и увеличиваются соответственно указанному шагу, и в кратных значениях указанного шага, но их непрерывность не гарантируется. Например, с начальным значением 0 и размером шага 2все значения - положительные четные числа, но некоторые числа могут быть пропущены.

При использовании предложения GENERATED BY DEFAULT AS IDENTITYоперации вставки могут указывать значения для столбца идентичности. Измените условие на GENERATED ALWAYS AS IDENTITY, чтобы переопределить возможность вручную задавать значения.

Колонки идентификаторов поддерживают только тип BIGINT, а операции завершаются ошибкой, если назначенное значение превышает диапазон, поддерживаемый BIGINT.

Сведения о синхронизации значений столбцов удостоверений с данными см. в ALTER TABLE ... COLUMN пункте.

Столбцы CTAS и столбцы идентификаторов

Невозможно определить схему, ограничения столбца с идентификатором или другие параметры таблицы при использовании оператора CREATE TABLE table_name AS SELECT (CTAS).

Чтобы создать новую таблицу со столбцом идентификаторов и заполнить её существующими данными, выполните следующие действия:

  1. Создайте таблицу с правильной схемой, включая определение столбца с идентичностью и другие свойства таблицы.
  2. Выполните операцию INSERT.

В следующем примере для определения столбца идентификаторов используется ключевое слово DEFAULT. Если данные, вставляемые в таблицу, содержат допустимые значения для столбца идентификаторов, эти значения используются.

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 (id, event_date, some_value)
SELECT id, event_date, some_value FROM old_table;

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

Ограничения столбцов идентификаторов

При работе с идентификационными столбцами существуют следующие ограничения:

  • Одновременные транзакции не поддерживаются в таблицах с включенными идентификационными столбцами.
  • Вы не можете секционировать таблицу по столбцу идентификаторов.
  • Нельзя использовать ALTER TABLE для ADD, REPLACE, или CHANGE идентификационного столбца.
  • Нельзя обновить значение столбца идентификатора для существующей записи.

Примечание.

Чтобы изменить значение IDENTITY для существующей записи, необходимо удалить эту запись и занести её INSERT как новую запись.

Созданные столбцы и маски столбцов

Созданный столбец не может ссылаться на столбец, имеющий маску столбца, примененную, так как созданное значение покажет базовые данные, защищенные маской. Это вызывает ошибку, и запрос завершается ошибкой. См. фильтры строк и маски столбцов.

Ниже приведены примеры ошибок:

  • Невозможно создать созданный столбец, выражение которого ссылается на маскированный столбец. COLUMN_MASKSВозвращает _GENERATED_COLUMN_UNSUPPORTED.

    CREATE TABLE tbl (
      a INT MASK masking_function,
      generated_col INT GENERATED ALWAYS AS (a + 1)
    ) USING DELTA;
    
  • Маску столбца нельзя применить к столбцу, который уже ссылается на созданный столбец. COLUMN_MASKSВызывает _REFERENCED_BY_GENERATED_COLUMN.ADD_MASK.

    CREATE TABLE tbl (
      a INT,
      generated_col INT GENERATED ALWAYS AS (a + 1)
    ) USING DELTA;
    
    ALTER TABLE tbl ALTER COLUMN a SET MASK masking_function;
    
  • Считывание из таблицы, в которой созданный столбец уже ссылается на маскированный столбец, также заблокировано. Вызывает COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN.READ_BLOCKED.

Чтобы устранить все эти ошибки, необходимо изменить таблицу, чтобы созданные столбцы и маскированные столбцы не перекрывались.