TTL на уровне строк
TTL на уровне строк — экспериментальная функция, поддерживаемая начиная с Apache Doris 5.0.0. Перед внедрением проверьте её в тестовой среде.
Включите TTL при создании таблицы: впоследствии его нельзя включить для существующей обычной таблицы, отключить или переключить на другой режим TTL. Для частичных обновлений столбцов, Sequence Columns и материализованных представлений действуют ограничения, описанные ниже. Истечение срока не гарантирует немедленное освобождение места на диске.
Обзор
TTL на уровне строк (Time to Live) делает отдельные строки невидимыми после истечения их срока и позволяет фоновой операции Compaction освободить их. Используйте его, когда для строк одной таблицы или раздела нужны разные сроки истечения. Поддерживаются встроенные таблицы с ключами Duplicate Key и Unique Key, включая Merge-on-Write (MOW) и Merge-on-Read (MOR), но не таблицы Aggregate Key.
Выбор режима TTL
При создании таблицы выберите один из следующих взаимоисключающих режимов:
| Сценарий использования | Режим | Конфигурация | Время истечения |
|---|---|---|---|
| Хранить каждое событие одинаковое время после его временной метки | Исходный столбец | Включить TTL и одновременно задать function_column.ttl_col и function_column.ttl | Временная метка источника + срок хранения таблицы |
| Позволить приложению назначать абсолютный срок для каждой строки | Прямое истечение | Включить TTL, не задавая ни одно из этих свойств | Абсолютное время истечения строки, записанное в __DORIS_TTL_COL__ |
Правила истечения
- Значение исходного столбца NULL или прямое время истечения NULL означает, что строка не истекает по TTL.
- Строка считается истёкшей, когда её время истечения меньше или равно текущему времени, используемому запросом.
- Каждый запрос использует одно значение текущего времени на протяжении всего сканирования. Поэтому последующий запрос может вернуть меньше строк даже без промежуточных записей.
Быстрый старт
Предварительные условия
- Используйте Apache Doris 5.0.0 или более поздней версии и проверьте экспериментальную функцию в тестовой среде.
- Подключитесь к тестовой базе данных под учётной записью с правами на создание, вставку и запросы к таблицам.
- Используйте поддерживаемую модель таблицы: встроенный Duplicate Key или Unique Key (MOW/MOR).
Создание таблицы и проверка истечения
В следующем примере каждое событие хранится один день после event_time. Настройка одной реплики предназначена только для этого примера и не является рекомендацией для производственной репликации.
SET time_zone = '+00:00';
DROP TABLE IF EXISTS row_ttl_events;
CREATE TABLE row_ttl_events (
id INT,
event_time DATETIME(6) NULL,
message STRING
)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"function_column.enable_row_ttl" = "true",
"function_column.ttl_col" = "event_time",
"function_column.ttl" = "1 day",
"function_column.ttl_time_zone" = "+00:00"
);
INSERT INTO row_ttl_events VALUES
(1, NOW(6) - INTERVAL 2 DAY, 'expired'),
(2, NULL, 'persistent'),
(3, NOW(6), 'live');
SELECT id, message FROM row_ttl_events ORDER BY id;
Сразу после вставки запрос возвращает:
id message
2 persistent
3 live
Старое событие уже невидимо без ожидания Compaction. Время события NULL не приводит к истечению. TTL рассчитывается по переданному времени события, а не автоматически по времени загрузки; событие, поступившее с опозданием, может истечь сразу после загрузки.
Параметры
Все перечисленные ниже свойства function_column.* имеют строковый тип и задаются как свойства таблицы.
| Свойство | Значение по умолчанию / условие обязательности | Значение и правила изменения |
|---|---|---|
function_column.enable_row_ttl | false; для включения любого режима задайте true | Строковое булево значение. Можно задать только при создании таблицы. |
function_column.ttl_col | Не задано; в режиме исходного столбца обязательно вместе с function_column.ttl | Имя существующего негенерируемого столбца Value типа DATE/DATEV2, DATETIME/DATETIMEV2 или TIMESTAMPTZ. Столбцы Key и TIMESTAMP_NS не поддерживаются. После создания изменить нельзя. |
function_column.ttl | Не задано; обязательно вместе с function_column.ttl_col | Неотрицательная длительность. После создания разрешается только та же или меньшая длительность. 0 означает истечение в момент времени источника, а не отключение TTL. В режиме прямого истечения недоступно. |
function_column.ttl_time_zone | Обязательно для исходных столбцов DATE/DATETIME; для TIMESTAMPTZ по умолчанию +00:00 | Часовой пояс для интерпретации исходных временных меток. Принимаются UTC, Z или фиксированное смещение от -12:00 до +14:00 в формате +HH:MM / -HH:MM. Для TIMESTAMPTZ допускается только нулевое смещение. После создания изменить нельзя; в режиме прямого истечения задавать нельзя. |
Формат длительности
Длительности без единицы измеряются в секундах. Регистр единиц не учитывается:
| Единица | Допустимые формы |
|---|---|
| Неделя | week, weeks |
| День | day, days, d |
| Час | hour, hours, h |
| Минута | minute, minutes, m |
| Секунда | second, seconds, s |
Например, 86400, 1 day и 24h обозначают одну и ту же длительность. День всегда равен 24 часам.
- Дробные и отрицательные значения, составные длительности вроде
1 day 2 hours, месяцы и годы отклоняются. - Длительность в микросекундах должна помещаться в знаковое 64-битное целое число.
- Сумма исходной временной метки и длительности также должна помещаться в знаковое 64-битное число микросекунд эпохи; при переполнении вычисление времени истечения завершается ошибкой.
Часовые пояса
В режиме исходного столбца региональные часовые пояса, такие как Asia/Shanghai, и правила летнего времени не поддерживаются. Значения DATE интерпретируются как полночь при настроенном смещении; значения TIMESTAMPTZ обозначают абсолютные моменты времени. Изменение часового пояса сеанса запроса не меняет политику TTL уже сохранённой строки.
Скрытый столбец TTL
Doris автоматически создаёт допускающий NULL скрытый столбец __DORIS_TTL_COL__. Не объявляйте его в схеме таблицы.
В режиме исходного столбца Doris копирует значение источника в этот скрытый столбец. Записывайте или обновляйте исходный столбец; не задавайте независимое время истечения через скрытый столбец.
В режиме прямого истечения скрытый столбец имеет тип BIGINT и хранит микросекунды с начала эпохи Unix, а не секунды или миллисекунды. Входные данные обрабатываются следующим образом:
| Входные данные | Поведение в режиме прямого истечения |
|---|---|
| NULL, DEFAULT или пропуск при полной вставке | Даёт NULL-время истечения, поэтому строка не истекает по TTL. |
| BIGINT | Используется непосредственно как микросекунды эпохи. Значения 0 и отрицательные значения уже истекли относительно текущего времени запросов. |
| Выражение DATE/DATETIME | Преобразуется в микросекунды эпохи с использованием time_zone сеанса SQL или timezone задания загрузки. |
| Выражение TIMESTAMPTZ | Преобразуется в микросекунды эпохи; значение уже представляет абсолютный момент времени. |
| Текстовая дата | Явно приведите к поддерживаемому временному типу. |
| TIMESTAMP_NS | Не поддерживается. |
Для просмотра включите show_hidden_columns и явно выберите скрытый столбец. Это не отключает фильтрацию TTL и не делает истёкшие строки видимыми.
Примеры
Назначение времени истечения каждой строке
Используйте режим прямого истечения, если приложение передаёт отдельное время истечения для каждой строки:
SET time_zone = '+00:00';
DROP TABLE IF EXISTS row_ttl_expirations;
CREATE TABLE row_ttl_expirations (id INT, message STRING)
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"function_column.enable_row_ttl" = "true"
);
INSERT INTO row_ttl_expirations(id, message, __DORIS_TTL_COL__) VALUES
(1, 'expired', 0),
(2, 'persistent', NULL),
(3, 'live', NOW(6) + INTERVAL 1 DAY);
INSERT INTO row_ttl_expirations VALUES (4, 'omitted');
SELECT id, message FROM row_ttl_expirations ORDER BY id;
Немедленный запрос возвращает:
id message
2 persistent
3 live
4 omitted
INSERT ... SELECT также принимает выражения временных типов для скрытого столбца и преобразует их по тем же правилам.
Загрузка временных меток истечения через Stream Load
Используйте таблицу row_ttl_expirations из предыдущего примера. Замените заполнители подключения и используйте учётную запись с правом загрузки. Входные данные содержат временную метку истечения, поэтому явно приведите её в сопоставлении столбцов и укажите часовой пояс загрузки:
curl --location-trusted -u '<user>:<password>' \
-H 'label:row_ttl_expirations_example_1' \
-H 'column_separator:,' \
-H 'timezone:+00:00' \
-H 'columns:id,message,expiration,__DORIS_TTL_COL__=cast(expiration as datetime(6))' \
-T - 'http://<fe_host>:<http_port>/api/<database>/row_ttl_expirations/_stream_load' <<'DATA'
10,stream-live,2099-01-01 00:00:00.000000
11,stream-expired,2000-01-01 00:00:00.000000
DATA
При повторной загрузке используйте новую метку. В успешном ответе Status равно Success; само истечение не превращает иным образом корректную входную строку в ошибку загрузки. До 2099 года следующий запрос возвращает только строку 10:
SELECT id, message FROM row_ttl_expirations WHERE id >= 10 ORDER BY id;
id message
10 stream-live
Если входные данные уже содержат микросекунды эпохи, сопоставьте их напрямую через columns:id,message,__DORIS_TTL_COL__, не преобразуя в DATETIME.
Обновление строки Unique Key
Обычный SQL UPDATE поддерживается. Для видимых строк изменение несвязанных столбцов сохраняет значение TTL; изменение исходной временной метки или прямого времени истечения меняет момент истечения строки. Это отличается от неподдерживаемых режимов загрузки с частичным обновлением столбцов.
DROP TABLE IF EXISTS row_ttl_accounts;
CREATE TABLE row_ttl_accounts (id INT, message STRING)
UNIQUE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"enable_unique_key_merge_on_write" = "true",
"function_column.enable_row_ttl" = "true"
);
INSERT INTO row_ttl_accounts(id, message, __DORIS_TTL_COL__) VALUES
(1, 'original', 9223372036854775807);
UPDATE row_ttl_accounts SET message = 'updated' WHERE id = 1;
SET show_hidden_columns = true;
SELECT id, message, __DORIS_TTL_COL__ FROM row_ttl_accounts ORDER BY id;
SET show_hidden_columns = false;
id message __DORIS_TTL_COL__
1 updated 9223372036854775807
Полный UPSERT строки заменяет строку целиком. Поэтому в режиме прямого истечения пропуск времени истечения очищает старое время:
INSERT INTO row_ttl_accounts(id, message) VALUES (1, 'replaced');
SET show_hidden_columns = true;
SELECT id, message, __DORIS_TTL_COL__ FROM row_ttl_accounts ORDER BY id;
SET show_hidden_columns = false;
id message __DORIS_TTL_COL__
1 replaced NULL
Учитывайте следующие правила обновления:
- В режиме исходного столбца полная вставка без исходного столбца использует обычные правила DEFAULT/NULL этого столбца, а не временную метку предыдущей версии строки.
- UPDATE не может найти уже истёкшую строку обычным запросом; чтобы записать новую версию, используйте полную вставку с нужными значениями.
- В таблицах Unique Key истечение новейшей версии не открывает снова старую версию того же ключа.
Сокращение срока хранения
Используйте таблицу с исходным столбцом из раздела «Быстрый старт» и учётную запись с правом ALTER:
ALTER TABLE row_ttl_events SET ("function_column.ttl" = "12 hours");
SHOW CREATE TABLE row_ttl_events;
Новый срок хранения применяется как к существующим значениям исходного столбца, так и к будущим записям. SHOW CREATE TABLE показывает обновлённое свойство function_column.ttl; длительности, отображаемые как целые числа без единицы, указаны в секундах.
Строки, которые по новой политике вышли за срок хранения, становятся невидимыми для запросов с этой политикой и пригодными для освобождения. Повторно задать ту же длительность разрешено; увеличение отклоняется, поскольку ранее истёкшие данные уже могли быть освобождены.
Более короткая политика запросов сохраняется до распространения настроек освобождения. Поэтому ALTER может сообщить о тайм-ауте, отсутствии подтверждения версии конфигурации или одновременном изменении таблицы уже после применения сокращённого срока хранения.
Проверьте SHOW CREATE TABLE, устраните указанную проблему и повторите операцию с той же длительностью, чтобы синхронизировать политику. Не пытайтесь восстановить прежнюю, более длинную длительность.
Ограничения
Перед включением TTL проверьте совместимость с существующими функциями таблицы и рабочими нагрузками:
| Область | Текущее поведение / ограничение |
|---|---|
| Модель таблицы | Поддерживаются только встроенные таблицы Duplicate Key и Unique Key (MOW/MOR); Aggregate Key отклоняется. |
| Включение и изменение режима | Включить можно только во время CREATE TABLE. ALTER не может включить или отключить TTL, изменить его исходный столбец или часовой пояс либо переключить режим. ENABLE FEATURE "ROW_TTL" не поддерживается. Сократить можно только срок хранения в режиме исходного столбца. |
| Sequence Column | Не может использоваться вместе с TTL на уровне строк, включая последующее включение SEQUENCE_LOAD. |
| Изменения схемы | Нельзя удалить или изменить исходный либо скрытый столбец TTL и переименовать исходный столбец. Изменения несвязанных столбцов по-прежнему подчиняются обычным правилам изменения схемы. |
| Частичные обновления столбцов | Не поддерживаются ни в одном режиме TTL. Сюда входят INSERT с enable_unique_key_partial_update = true, Stream Load с partial_columns = true, UPDATE_FIXED_COLUMNS и UPDATE_FLEXIBLE_COLUMNS, даже если запрос содержит значение TTL. Полный UPSERT, обычный SQL UPDATE и DELETE остаются доступными по обычным правилам модели таблицы. |
| Материализованные представления | CREATE MATERIALIZED VIEW для синхронных материализованных представлений отклоняется на таблицах с TTL; асинхронные материализованные представления не могут использовать таблицы TTL как базовые. Это отличается от обычного ALTER TABLE ... ADD ROLLUP, который поддерживается, а скрытый столбец TTL обслуживается Doris. |
| Исторический и инкрементальный доступ | В таблицах TTL не поддерживаются FOR VERSION AS OF, FOR TIME AS OF, @incr(...) и CREATE STREAM ... ON TABLE. |
| Подсказки запросов | PREAGGOPEN отклоняется. При сканировании MOR отключается предварительная агрегация на уровне хранилища, чтобы сохранить корректную семантику слияния версий и истечения. |
| Производительность запросов | При сканировании TTL отключаются SQL Cache, Query Cache, короткие точечные запросы и некоторые оптимизации проталкивания TopN. Точечные выборки, агрегаты, соединения и ORDER BY/LIMIT по-прежнему работают, но нельзя предполагать тот же план выполнения или производительность, что у таблицы без TTL. |
| Проверки согласованности | Автоматические проверки согласованности контрольных сумм пропускают таблицы TTL; явные проверки согласованности контрольных сумм для TTL-tablet отклоняются. Обычная репликация при этом не отключается. |
Границы физического освобождения
Видимость TTL проверяется во время запросов; освобождение места на диске зависит от подходящей фоновой Compaction и последующей очистки устаревших файлов. Простаивающая таблица, задержка Compaction или сохранение старых файлов могут оставить истёкшие данные на диске. Фиксированного срока удаления нет.
Освобождение зависит от модели таблицы и пути Compaction:
| Модель таблицы / путь данных | Поведение освобождения |
|---|---|
| Duplicate Key | Поддерживаемые пути segment, cumulative, base и full Compaction могут освобождать истёкшие строки. |
| Unique Key MOW | Cumulative, base и full Compaction могут освобождать истёкшие строки из опубликованных rowset. Segment Compaction до публикации сохраняет истёкшие ключи для разрешения конфликтов записи. |
| Unique Key MOR | Истёкшие строки освобождаются только при full Compaction или base Compaction, охватывающей версии начиная с 0; удаление не открывает старые версии того же ключа. |
| Compaction холодных данных | Освобождение по TTL строк не выполняется. |
| Changelog tablets | TTL строк не удаляет записи журнала. Необработанный Changelog может сохранять записи, строки которых в базовой таблице уже истекли; его хранение регулируется отдельно. |
TTL на уровне строк не гарантирует, что в момент истечения будут удалены все копии или записи изменений.
Устранение неполадок
Используйте следующие проверки при ошибках конфигурации или задержке освобождения хранилища:
| Ошибка / симптом | Действие |
|---|---|
function_column.ttl_col and function_column.ttl must be set together | Для режима исходного столбца задайте оба свойства, а для режима прямого истечения не задавайте ни одного. |
function_column.ttl_time_zone is required | Явно задайте фиксированное смещение для исходного столбца DATE/DATETIME. |
row ttl column must be a value column | Выберите поддерживаемый временной столбец Value, а не столбец Key. |
Partial update is not supported on tables with row TTL | Используйте полный UPSERT с намеренно заданными значениями по умолчанию для пропущенных столбцов или обычный SQL UPDATE; не удаляйте настройку частичного обновления, не проверив значения пропущенных столбцов. |
Increasing function_column.ttl is not supported | Сохраните или сократите длительность. Если требуется более длительное хранение, создайте новую таблицу и повторно загрузите данные из сохранённого источника; TTL не может восстановить уже освобождённые данные. |
TTL properties can only be specified when creating a table | Не изменяйте через ALTER флаг включения, исходный столбец или часовой пояс. В таблице TTL с исходным столбцом можно менять только function_column.ttl. |
| Строки исчезают, но размер хранилища не уменьшается | Проверьте ход Compaction и описанные выше границы освобождения. Истечение и физическое удаление — отдельные этапы. |
Лучшие практики
- Выбирайте режим исходного столбца, когда после каждого события нужно хранить данные одинаковое время, и режим прямого истечения, когда приложение назначает абсолютный срок для каждой строки. Перед загрузкой проверяйте запаздывающие временные метки и значения NULL.
- Если хранение естественным образом следует целым временным разделам, отдавайте предпочтение динамическому секционированию. TTL на уровне строк подходит для более детального управления, но добавляет фильтрацию каждой строки и ограничивает оптимизации запросов.
- Перед внедрением протестируйте реальные рабочие нагрузки загрузки, обновления, запросов и Compaction. Особенно проверьте зависимости от частичных обновлений, Sequence Columns, материализованных представлений, исторических запросов и кэширования.
- Перед сокращением срока хранения подтвердите нужную границу истечения и сохраните вне этой политики TTL все данные, которые должны оставаться восстанавливаемыми. Проверяйте видимость обычными запросами; размер на диске или просмотр скрытого столбца не доказывают ни истечение, ни полное удаление данных.