Привет, хабр! Меня зовут Кирилл Курдюков, я разработчик YDB.

В этой статье мы рассмотрим, как начать использовать диалект YDB (YQL) в Liquibase для управления миграциями схемы данных.

Введение

В современном мире разработки ПО управление версиями схемы данных стало критически важной задачей для обеспечения согласованности состояния СУБД с приложением клиента и отката изменений. Инструменты миграции базы данных, такие как Liquibase, предоставляют средства для версионирования, отслеживания и применения изменений схемы данных.

Однако, появление новых СУБД ставит задачу интеграции с этими системами для поддержки их диалектов SQL.

Как раз о результатах интеграции диалекта YDB c Liquibase мы и поговорим в этой статье.

Возможности диалекта YDB и переносимость стандарта описания changeset'ов Liquibase

Основной функциональностью Liquibase является абстрактное описание схемы базы данных в форматах .xml, .json, .yaml. Что обеспечивает переносимость при смене одной СУБД на другую.

Для YDB поддержаны следующее основные конструкции:

  1. createTable создание таблицы. Описание типов данных из SQL стандарта сопоставляется с примитивными типами YDB. К примеру, тип bigint будет конвертирован в Int64. Также можно явно указывать оригинальное название, например, такие типы как Uint32, Json, JsonDocument, Bytes, Interval. Но в таком случае теряется переносимость схемы на другие СУБД.

  2. dropIndex, createIndex, addColumn, dropTable. Соответственно, удаление, создание индекса и добавление колонки, удаление таблицы.

  3. loadData, loadUpdateData загрузка данных из CSV файлов.

  4. insert единичная вставка в таблицу.

На момент написания статьи есть ограничения с классическими конструкциями SQL. Например, в версии YDB 23.3 вторичный индекс не может быть уникальным.

Важно отметить, что кастомные инструкции YQL можно применять через нативные SQL запросы. Но YDB не стоит на месте! В дальнейшем все больше и больше классических SQL конструкций будет поддержано.

Чтобы понять, какие SQL-конструкции может выполнять YDB, ознакомьтесь с документацией по языку запросов YQL.

Как воспользоваться?

Есть два способа:

  • программно из Java / Kotlin приложения

  • liquibase CLI

Как воспользоваться из Java / Kotlin подробно описано в README проекта, там же есть ссылка на пример Spring Boot приложения.

Пример использования диалекта

Установка

Для начала нужно установить саму утилиту liquibase любым из рекомендуемых способов.
Затем нужно подложить актуальные .jar архивы YDB JDBC драйвера и Liquibase диалекта YDB.

# $(which liquibase)
cd ./internal/lib/

# you may need to sudo
# set an actual versions .jar files
curl -L -o ydb-jdbc-driver.jar https://repo.maven.apache.org/maven2/tech/ydb/jdbc/ydb-jdbc-driver-shaded/2.0.7/ydb-jdbc-driver-shaded-2.0.7.jar
curl -L -o liquibase-ydb-dialect.jar https://repo.maven.apache.org/maven2/tech/ydb/dialects/liquibase-ydb-dialect/1.0.0/liquibase-ydb-dialect-1.0.0.jar

Более подробное описание в разделе Manual library management. Теперь liquibase утилитой можно пользоваться стандартными способами.

Настройка

Напишем простенький liquibase.properties:

changelog-file=changelogs.xml
url=jdbc:ydb:grpc://localhost:2136/local
  • changelog-file - относительный путь к файлу миграций

  • url - локальный докер контейнер YDB

Создание первой таблицы

Создадим первую таблицу episodes и загрузим в нее из CSV файла данные.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                      http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

    <changeSet id="episodes" author="kurdyukov-kir">
        <comment>Table episodes.</comment>

        <createTable tableName="episodes">
            <column name="series_id" type="bigint">
                <constraints primaryKey="true"/>
            </column>
            <column name="season_id" type="bigint">
                <constraints primaryKey="true"/>
            </column>
            <column name="episode_id" type="bigint">
                <constraints primaryKey="true"/>
            </column>

            <column name="title" type="text"/>
            <column name="air_date" type="timestamp"/>
        </createTable>

        <createIndex tableName="episodes" indexName="episodes_index" unique="false">
            <column name="title"/>
        </createIndex>

        <rollback>
            <dropTable tableName="episodes"/>
        </rollback>
    </changeSet>
</databaseChangeLog>

Содержимое файла changelogs.xml :

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                      http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

    <include file="migration/episodes.xml" relativeToChangelogFile="true"/>
    <changeSet id="episodes-from-csv" author="kurdyukov-kir" context="all">
        <loadData tableName="episodes" file="./migration/csv/episodes.csv" relativeToChangelogFile="true"/>
    </changeSet>
</databaseChangeLog>

После исполнения liquibase update Liquibase напечатает лог исполненных миграций.

Running Changeset: migration/episodes.xml::episodes::kurdyukov-kir
Running Changeset: changelogs.xml::episodes-from-csv::kurdyukov-kir

UPDATE SUMMARY
Run:                          2
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            2

Результатом будет таблица episodes c добавленными записями:

Схема базы данных
Схема базы данных

Далее в своей базе данных можно увидеть созданные Liquibase две системные таблицы: DATABASECHANGELOG, DATABASECHANGELOGLOCK.

Эволюционируем таблицу episodes

Далее допустим, что наша схема базы данных нуждается в дополнительных изменениях:

  • Добавим новую колонку is_deleted типа Bool.

  • Удалим индекс.

Допишем в changelogs.xml следующий changeset:

<changeSet id="alter-episodes" author="kurdyukov-kir">
    <comment>Alter table episodes.</comment>

    <dropIndex tableName="episodes" indexName="episodes_index"/>

    <addColumn tableName="episodes">
        <column name="is_deleted" type="bool"/>
    </addColumn>
</changeSet>

Лог команды liquibase update:

Running Changeset: changelogs.xml::alter-episodes::kurdyukov-kir

UPDATE SUMMARY
Run:                          1
Previously run:               2
Filtered out:                 0
-------------------------------
Total change sets:            3

Результатом будет добавление новой колонки is_deleted и удаление индекса:

Удаление индекса episodes_index и добавление колонки is_deleted
Удаление индекса episodes_index и добавление колонки is_deleted

Миграция нативных YQL конструкций

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

--liquibase formatted sql

--changeset kurdyukov-kir:create-a-topic
CREATE TOPIC `my_topic` (
    CONSUMER my_consumer
) WITH (
     retention_period = Interval('P1D')
);

ALTER TABLE episodes SET (AUTO_PARTITIONING_BY_SIZE = DISABLED);

Changeset соответствующий:

<include file="/migration/sql/yql.sql" relativeToChangelogFile="true"/>

Лог выполнения миграций:

Running Changeset: migration/sql/yql.sql::create-topic::kurdyukov-kir
Running Changeset: migration/sql/yql.sql::auto-partitioning-disabled::kurdyukov-kir

UPDATE SUMMARY
Run:                          2
Previously run:               3
Filtered out:                 0
-------------------------------
Total change sets:            5

Результатом будет создание топика my_topic и выключение автоматического партицирования:

Добавление топика my_topic и  выключение автопартицирования
Добавление топика my_topic и выключение автопартицирования

Поддержка и контакты

Если вы столкнулись с какой-то проблемой или у вас есть идея по улучшению диалекта, то можно открыть issue в репозитории ydb-java-dialects с тэгом liquibase.

Либо приходите обсудить её в публичный Telegram чат YDB.

Комментарии (0)