This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 1fe3a22bd539 [doc](docs) Document row-level TTL and limitations (#4544)
1fe3a22bd539 is described below

commit 1fe3a22bd5392f5ee86fba8afcc0a24e883dc059
Author: Jingzhe Jia <[email protected]>
AuthorDate: Thu Oct 29 15:05:56 2026 +0800

    [doc](docs) Document row-level TTL and limitations (#4544)
    
    ## Summary
    
    Document row-level TTL in English and Chinese. The page titles omit the
    experimental label; the opening notices identify it as an experimental
    feature supported since Apache Doris 5.0.0.
    
    Organize the guides around TTL mode selection, prerequisites, duration
    and time-zone settings, hidden-column inputs, reclamation boundaries,
    and troubleshooting. Preserve the existing SQL, commands, expected
    outputs, and technical restrictions, and improve SEO metadata and
    internal links.
    
    ## Versions
    
    - [x] dev
    - [ ] 4.x
    - [ ] 3.x
    - [ ] 2.1 or older (not covered by version/language sync gate)
    
    ## Languages
    
    - [x] Chinese
    - [x] English
    
    ## Docs Checklist
    
    - [x] Checked by AI
    - [ ] Test Cases Built
    - [x] Updated required version and language counterparts, or explained
    why not
    - [ ] If only one language changed, confirmed whether source/translation
    counterparts need sync
    
    ## Version scope
    
    This PR updates dev/current documentation only. Row-level TTL is
    supported since Apache Doris 5.0.0, so 4.x, 3.x, and 2.1 documentation
    counterparts are intentionally omitted. The English and Chinese guides
    are updated together.
    
    ## Validation
    
    - Docusaurus compilation passed for both guides; all 13 original heading
    anchors in each guide are preserved.
    - All 12 code and output blocks in each guide are unchanged, and
    English/Chinese examples match exactly. Internal links and SEO metadata
    were checked; there are no external links or images.
    - Docs governance reports only the expected missing-4.x warning, covered
    by the version scope above. SQL examples were preserved and were not
    executed against a cluster.
    
    ---------
    
    Co-authored-by: morningman <[email protected]>
---
 docs/data-operate/delete/row-ttl.md                | 337 +++++++++++++++++++++
 .../current/data-operate/delete/row-ttl.md         | 337 +++++++++++++++++++++
 sidebars.ts                                        |   1 +
 3 files changed, 675 insertions(+)

diff --git a/docs/data-operate/delete/row-ttl.md 
b/docs/data-operate/delete/row-ttl.md
new file mode 100644
index 000000000000..f03fb16a7346
--- /dev/null
+++ b/docs/data-operate/delete/row-ttl.md
@@ -0,0 +1,337 @@
+---
+{
+    "title": "Row-level TTL",
+    "language": "en",
+    "description": "Configure row-level TTL in Apache Doris to expire rows by 
source timestamps or per-row deadlines, and manage retention.",
+    "keywords": ["row-level TTL", "data expiration", "retention", 
"experimental", "Compaction", "row TTL", "Time to Live", "automatic data 
expiration", "per-row expiration", "data retention", 
"function_column.enable_row_ttl", "Doris 5.0.0"],
+    "doc_type": "feature"
+}
+---
+
+:::caution Experimental feature
+
+Row-level TTL is an experimental feature supported since Apache Doris 5.0.0. 
Validate it in a test environment before adopting it.
+
+Enable TTL when creating the table: it cannot subsequently be enabled on an 
existing ordinary table, disabled, or switched to another TTL mode. Partial 
column updates, Sequence Columns, and materialized views have restrictions 
described below. Expiration does not guarantee immediate disk-space reclamation.
+
+:::
+
+<!-- Knowledge Type: Feature Overview -->
+<!-- Use Case: Row-level Data Expiration -->
+## Overview
+
+Row-level TTL (Time to Live) makes individual rows invisible after their 
expiration time and allows background Compaction to reclaim them. Use it when 
rows in the same table or partition need different expiration times. It 
supports native Duplicate Key and Unique Key tables, including Merge-on-Write 
(MOW) and Merge-on-Read (MOR), but not Aggregate Key tables.
+
+### Choose a TTL mode
+
+Choose one of these mutually exclusive modes when creating the table:
+
+| Use case | Mode | Configuration | Expiration time |
+| --- | --- | --- | --- |
+| Retain each event for the same duration after its timestamp | Source column 
| Enable TTL and set `function_column.ttl_col` and `function_column.ttl` 
together | Source timestamp + table retention duration |
+| Let the application assign an absolute deadline to each row | Direct 
expiration | Enable TTL without setting either of those properties | Per-row 
absolute expiration written to `__DORIS_TTL_COL__` |
+
+### Expiration rules
+
+- A NULL source value or NULL direct expiration means the row does not expire 
through TTL.
+- A row is expired when its expiration time is **less than or equal to** the 
current time used by the query.
+- Each query uses one current-time value throughout the scan. A later query 
can therefore return fewer rows without any intervening writes.
+
+<!-- Knowledge Type: Operational Steps -->
+<!-- Use Case: Configure Source-column TTL -->
+## Quick Start
+
+### Prerequisites
+
+- Use Apache Doris 5.0.0 or later and validate the experimental feature in a 
test environment.
+- Connect to a test database using an account with permission to create, 
insert into, and query tables.
+- Use a supported table model: native Duplicate Key or Unique Key (MOW/MOR).
+
+### Create a table and verify expiration
+
+The following example retains each event for one day after `event_time`. The 
single-replica setting is for this example, not a production replication 
recommendation.
+
+```sql
+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;
+```
+
+Querying immediately after insertion returns:
+
+```text
+id  message
+2   persistent
+3   live
+```
+
+The old event is already invisible without waiting for Compaction. The NULL 
event time does not expire. TTL is based on the supplied event time, not 
automatically on the load time; a late-arriving event can be expired as soon as 
it is loaded.
+
+<!-- Knowledge Type: Configuration Parameters -->
+## Parameters
+
+All `function_column.*` properties below are string-valued table properties.
+
+| Property | Default / required condition | Meaning and modification rules |
+| --- | --- | --- |
+| `function_column.enable_row_ttl` | `false`; set to `true` to enable either 
mode | Boolean string. Can only be set when creating the table. |
+| `function_column.ttl_col` | Unset; required together with 
`function_column.ttl` in source-column mode | Name of an existing non-generated 
Value column of type DATE/DATEV2, DATETIME/DATETIMEV2, or TIMESTAMPTZ. Key 
columns and TIMESTAMP_NS are not supported. Cannot be changed after creation. |
+| `function_column.ttl` | Unset; required together with 
`function_column.ttl_col` | Nonnegative integer duration. After creation, only 
the same or a shorter duration is allowed. `0` means expiration at the source 
timestamp, **not disabling TTL**. Unavailable in direct-expiration mode. |
+| `function_column.ttl_time_zone` | Required for DATE/DATETIME-family source 
columns; defaults to `+00:00` for TIMESTAMPTZ | Time zone for interpreting 
source timestamps. Accepts `UTC`, `Z`, or a fixed offset from `-12:00` to 
`+14:00` in `+HH:MM` / `-HH:MM` form. TIMESTAMPTZ permits only zero offset. 
Cannot be changed after creation or set in direct-expiration mode. |
+
+### Duration format
+
+Durations without a unit are seconds. Units are case-insensitive:
+
+| Unit | Accepted forms |
+| --- | --- |
+| Week | `week`, `weeks` |
+| Day | `day`, `days`, `d` |
+| Hour | `hour`, `hours`, `h` |
+| Minute | `minute`, `minutes`, `m` |
+| Second | `second`, `seconds`, `s` |
+
+For example, `86400`, `1 day`, and `24h` represent the same duration. A day is 
a fixed 24 hours.
+
+- Fractions, negative values, compound durations such as `1 day 2 hours`, 
months, and years are rejected.
+- The duration must fit in signed 64-bit microseconds.
+- The source timestamp plus the duration must also fit in signed 64-bit epoch 
microseconds; an overflow causes expiration calculation to fail.
+
+### Time zones
+
+In source-column mode, regional time zones such as `Asia/Shanghai` and 
daylight-saving rules are not supported. DATE values are interpreted at 
midnight in the configured offset; TIMESTAMPTZ values represent absolute 
instants. Changing the query session's time zone does not change an already 
stored row's TTL policy.
+
+### Hidden TTL column
+
+Doris creates the nullable hidden column `__DORIS_TTL_COL__` automatically. Do 
not declare it in the table schema.
+
+In source-column mode, Doris copies the source value into this hidden column. 
Write or update the source column; do not supply an independent expiration 
through the hidden column.
+
+In direct-expiration mode, the hidden column is BIGINT, storing **microseconds 
since the Unix epoch**, not seconds or milliseconds. Inputs are handled as 
follows:
+
+| Input | Behavior in direct-expiration mode |
+| --- | --- |
+| NULL, DEFAULT, or omission during a full insert | Gives a NULL expiration, 
so the row does not expire through TTL. |
+| BIGINT | Used directly as epoch microseconds. `0` and negative values are 
already expired at present-day query times. |
+| DATE/DATETIME expression | Converted to epoch microseconds using the SQL 
session's `time_zone` or the load job's `timezone`. |
+| TIMESTAMPTZ expression | Converted to epoch microseconds; the value already 
represents an absolute instant. |
+| Textual date | Cast explicitly to a supported temporal type. |
+| TIMESTAMP_NS | Not supported. |
+
+For inspection, enable `show_hidden_columns` and explicitly select the hidden 
column. This does **not** bypass TTL filtering or make expired rows visible.
+
+<!-- Knowledge Type: Operational Steps -->
+<!-- Use Case: Load and Update Row Expiration Times -->
+## Examples
+
+### Assign an expiration to each row
+
+Use direct-expiration mode when the application supplies a separate expiration 
time for each row:
+
+```sql
+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;
+```
+
+Querying immediately returns:
+
+```text
+id  message
+2   persistent
+3   live
+4   omitted
+```
+
+`INSERT ... SELECT` also accepts temporal expressions for the hidden column 
and converts them using the same rules.
+
+### Load expiration timestamps with Stream Load
+
+Use the `row_ttl_expirations` table above. Replace the connection placeholders 
and use an account with load permission. The input contains an expiration 
timestamp, so explicitly cast it in the column mapping and specify the load 
time zone:
+
+```bash
+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
+```
+
+Use a new label if repeating the load. A successful response has `Status` 
equal to `Success`; expiration itself does not make an otherwise valid input 
row a load error. Before 2099, the following query returns only row 10:
+
+```sql
+SELECT id, message FROM row_ttl_expirations WHERE id >= 10 ORDER BY id;
+```
+
+```text
+id  message
+10  stream-live
+```
+
+If the input already contains epoch **microseconds**, map it directly with 
`columns:id,message,__DORIS_TTL_COL__` instead of casting it to DATETIME.
+
+### Update a Unique Key row
+
+Ordinary SQL UPDATE is supported. For visible rows, changing unrelated columns 
preserves the TTL value; changing the source timestamp or direct expiration 
changes when the row expires. This differs from the unsupported partial column 
update load modes.
+
+```sql
+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;
+```
+
+```text
+id  message  __DORIS_TTL_COL__
+1   updated  9223372036854775807
+```
+
+A full-row UPSERT replaces the row. In direct-expiration mode, omitting the 
expiration therefore clears the old expiration:
+
+```sql
+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;
+```
+
+```text
+id  message   __DORIS_TTL_COL__
+1   replaced  NULL
+```
+
+Keep these update rules in mind:
+
+- In source-column mode, a full insert that omits the source uses that 
column's normal default/NULL rules, not the previous row's timestamp.
+- An UPDATE cannot find an already expired row through an ordinary query; use 
a full insert with the desired values to write a new version.
+- On Unique Key tables, expiration of the newest version does not reveal an 
older version of the same key.
+
+### Shorten retention
+
+Using the source-column table from Quick Start and an account with ALTER 
permission:
+
+```sql
+ALTER TABLE row_ttl_events SET ("function_column.ttl" = "12 hours");
+SHOW CREATE TABLE row_ttl_events;
+```
+
+The new retention applies to existing source values as well as future writes. 
`SHOW CREATE TABLE` shows the updated `function_column.ttl` property; durations 
shown as unitless integers are in seconds.
+
+Rows newly outside the retention period become invisible to queries using the 
new policy and eligible for reclamation. Setting the same duration again is 
allowed; increasing it is rejected because previously expired data may already 
have been reclaimed.
+
+:::caution Failed ALTER does not imply rollback
+
+The shorter query policy is persisted before reclamation settings are 
distributed. An ALTER can report a timeout, a missing configuration-version 
acknowledgment, or a concurrent table change after the shorter retention has 
taken effect.
+
+Check `SHOW CREATE TABLE`, resolve the reported issue, and retry with the same 
duration to synchronize the policy. Do not attempt to restore the old, longer 
duration.
+
+:::
+
+<!-- Knowledge Type: Feature Constraints -->
+## Limitations
+
+Check compatibility with existing table features and workloads before enabling 
TTL:
+
+| Area | Current behavior / restriction |
+| --- | --- |
+| Table model | Native Duplicate Key and Unique Key (MOW/MOR) tables only; 
Aggregate Key is rejected. |
+| Enabling and changing mode | Enable only at CREATE TABLE time. ALTER cannot 
enable/disable TTL, change its source or time zone, or switch modes. `ENABLE 
FEATURE "ROW_TTL"` is not supported. Only source-column retention can be 
shortened. |
+| Sequence Column | Cannot coexist with row TTL, including enabling 
`SEQUENCE_LOAD` afterward. |
+| Schema changes | Cannot drop or modify the TTL source or hidden column, or 
rename the source column. Unrelated column changes remain subject to normal 
schema-change rules. |
+| Partial column updates | Not supported for either TTL mode. This includes 
INSERT with `enable_unique_key_partial_update = true`, Stream Load 
`partial_columns = true`, `UPDATE_FIXED_COLUMNS`, and 
`UPDATE_FLEXIBLE_COLUMNS`, even when the request supplies a TTL value. Full 
UPSERT, ordinary SQL UPDATE, and DELETE remain available under their normal 
table-model rules. |
+| Materialized views | `CREATE MATERIALIZED VIEW` for synchronous materialized 
views is rejected on TTL tables; asynchronous materialized views cannot use TTL 
base tables. This is distinct from ordinary `ALTER TABLE ... ADD ROLLUP`, which 
is supported with the TTL hidden column maintained by Doris. |
+| Historical and incremental access | `FOR VERSION AS OF`, `FOR TIME AS OF`, 
`@incr(...)`, and `CREATE STREAM ... ON TABLE` are not supported on TTL tables. 
|
+| Query hints | `PREAGGOPEN` is rejected. MOR scans disable storage 
preaggregation to preserve version-merge and expiration semantics. |
+| Query performance | SQL Cache, Query Cache, short-circuit point queries, and 
certain TopN pushdowns are disabled for TTL scans. Point lookups, aggregates, 
joins, and ORDER BY/LIMIT still work, but do not assume the same execution plan 
or performance as a non-TTL table. |
+| Consistency checks | Automatic checksum consistency checks skip TTL tables; 
explicit checksum consistency checks for TTL tablets are rejected. This does 
not disable ordinary replication. |
+
+<!-- Knowledge Type: Data Reclamation Behavior -->
+## Physical reclamation boundaries
+
+TTL visibility is checked during queries; disk reclamation depends on eligible 
background Compaction and subsequent obsolete-file cleanup. An idle table, 
delayed Compaction, or retained old files can leave expired data on disk. There 
is no fixed deletion deadline.
+
+Reclamation depends on the table model and Compaction path:
+
+| Table model / data path | Reclamation behavior |
+| --- | --- |
+| Duplicate Key | Supported segment, cumulative, base, and full Compaction 
paths can reclaim expired rows. |
+| Unique Key MOW | Cumulative, base, and full Compaction can reclaim expired 
rows from published rowsets. Pre-publication segment Compaction keeps expired 
keys for write-conflict resolution. |
+| Unique Key MOR | Only full Compaction or base Compaction covering versions 
from 0 reclaims expired rows, so removal does not reveal older versions of the 
same key. |
+| Cold-data Compaction | Does not perform row-TTL reclamation. |
+| Changelog tablets | Do not apply row TTL to remove log entries. Raw 
Changelog can retain writes whose base-table rows have expired; its retention 
is separate. |
+
+Row TTL is not a guarantee that every copy or change record is erased at 
expiration.
+
+<!-- Knowledge Type: Troubleshooting -->
+<!-- Use Case: Resolve TTL Configuration Errors and Reclamation Delays -->
+## Troubleshooting {#error-handling}
+
+Use the following checks for configuration errors or delayed storage 
reclamation:
+
+| Error / symptom | Action |
+| --- | --- |
+| `function_column.ttl_col and function_column.ttl must be set together` | 
Supply both for source-column mode, or omit both for direct-expiration mode. |
+| `function_column.ttl_time_zone is required` | Set an explicit fixed offset 
for a DATE/DATETIME source column. |
+| `row ttl column must be a value column` | Choose a supported temporal Value 
column, not a Key column. |
+| `Partial update is not supported on tables with row TTL` | Use full UPSERT 
with intentional defaults for omitted columns, or ordinary SQL UPDATE; do not 
simply remove the partial-update setting without checking omitted values. |
+| `Increasing function_column.ttl is not supported` | Retain or shorten the 
duration. Plan a new table and reload from a retained source if longer 
retention is required; TTL cannot restore reclaimed data. |
+| `TTL properties can only be specified when creating a table` | Do not ALTER 
the enable flag, source, or time zone. Only `function_column.ttl` can be 
changed on a source-column TTL table. |
+| Rows disappear but storage size does not decrease | Check Compaction 
progress and the reclamation boundaries above. Expiration and physical deletion 
are separate. |
+
+<!-- Knowledge Type: Architecture Decision -->
+## Best Practices
+
+- Choose source-column mode for a uniform duration after each event, and 
direct-expiration mode when the application assigns an absolute deadline per 
row. Check late-arriving timestamps and NULL values before loading.
+- Prefer [dynamic 
partitioning](../../table-design/data-partitioning/dynamic-partitioning) when 
retention naturally follows whole time partitions. Row TTL is useful for finer 
granularity, but adds per-row filtering and constrains query optimizations.
+- Test actual ingestion, update, query, and Compaction workloads before 
adoption. In particular, check dependencies on partial updates, Sequence 
Columns, materialized views, historical queries, and caching.
+- Before shortening retention, confirm the intended cutoff and retain any data 
that must remain recoverable outside this TTL policy. Validate visibility with 
normal queries; do not treat disk usage or hidden-column inspection as proof of 
expiration or complete erasure.
diff --git 
a/i18n/zh-CN/docusaurus-plugin-content-docs/current/data-operate/delete/row-ttl.md
 
b/i18n/zh-CN/docusaurus-plugin-content-docs/current/data-operate/delete/row-ttl.md
new file mode 100644
index 000000000000..41d144d2e6e4
--- /dev/null
+++ 
b/i18n/zh-CN/docusaurus-plugin-content-docs/current/data-operate/delete/row-ttl.md
@@ -0,0 +1,337 @@
+---
+{
+    "title": "行级 TTL",
+    "language": "zh-CN",
+    "description": "Apache Doris 5.0.0 起支持的实验性行级 TTL 
使用指南:按源列保留时长或逐行过期时间管理数据,提供建表、Stream Load 导入和更新示例,说明 NULL 行为、表模型、查询优化及物理回收限制。",
+    "keywords": ["行级 TTL", "数据过期", "保留时长", "实验性", "Compaction", "row-level 
TTL", "Time to Live", "自动数据过期", "逐行过期时间", "数据生命周期管理", 
"function_column.enable_row_ttl", "Doris 5.0.0"],
+    "doc_type": "feature"
+}
+---
+
+:::caution 实验性功能
+
+行级 TTL 是实验性功能,自 Apache Doris 5.0.0 起支持。采用前请先在测试环境中验证。
+
+TTL 必须在建表时开启:不能为已有普通表补开,不能关闭,也不能切换 TTL 模式。部分列更新、Sequence 
列和物化视图等存在下文所列限制。数据过期不保证磁盘空间立即释放。
+
+:::
+
+<!-- 知识类型: 功能概述 -->
+<!-- 适用场景: 行级数据过期管理 -->
+## 概述
+
+行级 TTL(Time to Live)使单行数据在过期后对查询不可见,并允许后台 Compaction 
回收过期行。它适用于同一张表或同一个分区内各行需要不同过期时间的场景。目前支持 Doris 内表的 Duplicate Key 和 Unique Key 
模型,包括写时合并(MOW)和读时合并(MOR),不支持 Aggregate Key 模型。
+
+### 选择 TTL 模式
+
+建表时,根据数据的保留需求选择以下两种互斥模式之一:
+
+| 适用场景 | 模式 | 配置方式 | 过期时间 |
+| --- | --- | --- | --- |
+| 每条事件从其时间戳起保留相同的时长 | 源列模式 | 开启 TTL,同时设置 `function_column.ttl_col` 和 
`function_column.ttl` | 源列时间 + 表级保留时长 |
+| 应用为每行指定绝对过期时间 | 直接过期时间模式 | 开启 TTL,不设置上述两个属性 | 写入 `__DORIS_TTL_COL__` 
的逐行绝对过期时间 |
+
+### 过期规则
+
+- 源列值或直接过期时间为 NULL 时,该行不会因 TTL 过期。
+- 过期时间**小于或等于**查询使用的当前时间时,该行即为过期。
+- 一次查询在整个扫描过程中使用统一的当前时间值。因此,即使没有新写入,后续查询也可能返回更少的行。
+
+<!-- 知识类型: 操作步骤 -->
+<!-- 适用场景: 配置源列模式 TTL -->
+## 快速开始
+
+### 前置条件
+
+- 使用 Apache Doris 5.0.0 或更高版本,并在测试环境中验证此实验性功能。
+- 使用有建表、写入和查询权限的账号连接测试数据库。
+- 使用受支持的表模型:Doris 内表的 Duplicate Key 或 Unique Key(MOW/MOR)。
+
+### 建表并验证过期行为
+
+以下示例使每条事件从 `event_time` 起保留一天。单副本配置仅用于演示,不是生产环境的副本数建议。
+
+```sql
+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;
+```
+
+写入后立即查询,结果为:
+
+```text
+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 自动创建可空隐藏列 `__DORIS_TTL_COL__`,不要在表结构中手动声明此列。
+
+在源列模式下,Doris 将源列值复制到隐藏列。应写入或更新源列,不要通过隐藏列提供独立的过期时间。
+
+在直接过期时间模式下,隐藏列类型为 BIGINT,保存 **Unix 纪元以来的微秒数**,不是秒或毫秒。各类输入的处理方式如下:
+
+| 输入 | 直接过期时间模式下的行为 |
+| --- | --- |
+| 完整行写入时传入 NULL、DEFAULT 或省略此列 | 得到 NULL 过期时间,该行不会因 TTL 过期。 |
+| BIGINT | 直接作为纪元微秒数使用。在当前日期查询时,`0` 和负值已经过期。 |
+| DATE/DATETIME 表达式 | 使用 SQL 会话的 `time_zone` 或导入任务的 `timezone` 转换为纪元微秒数。 |
+| TIMESTAMPTZ 表达式 | 转换为纪元微秒数;该值本身已表示绝对时间。 |
+| 文本日期 | 应显式转换为支持的时间类型。 |
+| TIMESTAMP_NS | 不支持。 |
+
+需要查看隐藏列时,开启 `show_hidden_columns` 并显式查询该列。此设置**不会**绕过 TTL 过滤,也不能用来查看已过期行。
+
+<!-- 知识类型: 操作步骤 -->
+<!-- 适用场景: 导入和更新逐行过期时间 -->
+## 示例
+
+### 为每行指定过期时间
+
+应用需要为每行指定不同的过期时间时,使用直接过期时间模式:
+
+```sql
+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;
+```
+
+立即查询,结果为:
+
+```text
+id  message
+2   persistent
+3   live
+4   omitted
+```
+
+`INSERT ... SELECT` 也支持向隐藏列写入时间类型表达式,转换规则相同。
+
+### 通过 Stream Load 导入过期时间
+
+使用上例的 `row_ttl_expirations` 
表。替换连接参数占位符,并使用有导入权限的账号。输入中包含过期时间字符串,因此在列映射中显式转换类型,同时指定导入时区:
+
+```bash
+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
+```
+
+重复导入时请使用新的 label。成功响应中的 `Status` 为 `Success`;过期本身不会使其他方面合法的输入行成为导入错误。在 2099 
年之前执行以下查询,仅返回第 10 行:
+
+```sql
+SELECT id, message FROM row_ttl_expirations WHERE id >= 10 ORDER BY id;
+```
+
+```text
+id  message
+10  stream-live
+```
+
+如果输入已经是纪元**微秒数**,应使用 `columns:id,message,__DORIS_TTL_COL__` 直接映射,不要再转换为 
DATETIME。
+
+### 更新 Unique Key 行
+
+支持普通 SQL UPDATE。对于可见行,修改无关列会保留 TTL 值;修改源列时间或直接过期时间会改变该行的到期时间。这与不支持的部分列更新导入模式不同。
+
+```sql
+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;
+```
+
+```text
+id  message  __DORIS_TTL_COL__
+1   updated  9223372036854775807
+```
+
+完整行 UPSERT 会替换整行。因此,直接过期时间模式下省略过期时间会清除旧的过期时间:
+
+```sql
+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;
+```
+
+```text
+id  message   __DORIS_TTL_COL__
+1   replaced  NULL
+```
+
+更新时还需注意以下规则:
+
+- 源列模式下,完整行写入省略源列时使用该列正常的默认值/NULL 规则,而不是上一版本的时间戳。
+- UPDATE 无法通过普通查询找到已经过期的行;如需写入新版本,应使用包含所需值的完整行 INSERT。
+- 对于 Unique Key 表,最新版本过期不会让同一 Key 的旧版本重新可见。
+
+### 缩短保留时长
+
+使用快速开始中的源列模式表,并使用有 ALTER 权限的账号:
+
+```sql
+ALTER TABLE row_ttl_events SET ("function_column.ttl" = "12 hours");
+SHOW CREATE TABLE row_ttl_events;
+```
+
+新的保留时长既作用于已有源列值,也作用于后续写入。`SHOW CREATE TABLE` 会显示更新后的 `function_column.ttl` 
属性;若显示的是不带单位的整数,则单位为秒。
+
+按新策略已经过期的行对使用该策略的查询不可见,并可被回收。允许再次设置相同的时长;不允许增大,因为先前过期的数据可能已经被回收。
+
+:::caution ALTER 报错不代表策略已回滚
+
+更短的查询策略会先持久化,再下发回收配置。因此,即使 ALTER 返回超时、配置版本未获确认或表发生并发变更等错误,更短的保留时长也可能已经生效。
+
+请检查 `SHOW CREATE TABLE`,排除报错原因后,以相同的时长重试以同步策略。不要尝试恢复原来更长的时长。
+
+:::
+
+<!-- 知识类型: 功能限制 -->
+## 限制
+
+开启 TTL 前,请检查现有表功能和工作负载是否满足以下限制:
+
+| 方面 | 当前行为 / 限制 |
+| --- | --- |
+| 表模型 | 仅支持 Doris 内表的 Duplicate Key 和 Unique Key(MOW/MOR);拒绝 Aggregate Key。 |
+| 开启及模式修改 | 仅能在 CREATE TABLE 时开启。ALTER 不能开启/关闭 TTL、改变源列或时区,也不能切换模式。不支持 `ENABLE 
FEATURE "ROW_TTL"`。只有源列模式的保留时长可以缩短。 |
+| Sequence 列 | 不能与行级 TTL 共存,包括建表后再开启 `SEQUENCE_LOAD`。 |
+| 表结构变更 | 不能删除或修改 TTL 源列、隐藏列,不能重命名源列。无关列的变更仍遵循普通 Schema Change 规则。 |
+| 部分列更新 | 两种 TTL 模式均不支持。包括开启 `enable_unique_key_partial_update = true` 的 
INSERT、Stream Load 的 `partial_columns = true`、`UPDATE_FIXED_COLUMNS` 和 
`UPDATE_FLEXIBLE_COLUMNS`,即使请求中带有 TTL 值也不支持。完整行 UPSERT、普通 SQL UPDATE 和 DELETE 
仍可按各自的表模型规则使用。 |
+| 物化视图 | 不允许在 TTL 表上通过 `CREATE MATERIALIZED VIEW` 创建同步物化视图;异步物化视图不能以 TTL 
表作为基表。这与普通 `ALTER TABLE ... ADD ROLLUP` 不同,后者受支持,TTL 隐藏列由 Doris 维护。 |
+| 历史及增量访问 | TTL 表不支持 `FOR VERSION AS OF`、`FOR TIME AS OF`、`@incr(...)` 和 
`CREATE STREAM ... ON TABLE`。 |
+| 查询 Hint | 拒绝 `PREAGGOPEN`。MOR 扫描会关闭存储层预聚合,以保证版本合并和过期语义正确。 |
+| 查询性能 | TTL 扫描会关闭 SQL Cache、Query Cache、短路点查以及部分 TopN 下推优化。点查、聚合、关联和 ORDER 
BY/LIMIT 仍可使用,但不能假定其执行计划和性能与普通表相同。 |
+| 一致性检查 | 自动校验和一致性检查会跳过 TTL 表;对 TTL Tablet 显式发起的校验和一致性检查会被拒绝。这不表示关闭普通副本复制。 |
+
+<!-- 知识类型: 数据回收行为 -->
+## 物理回收边界
+
+查询时检查 TTL 可见性;磁盘回收则依赖适用的后台 Compaction 和后续旧文件清理。表长期没有合并、Compaction 
延迟或旧文件仍被保留,都可能导致过期数据继续占用磁盘,没有固定的物理删除时限。
+
+回收行为取决于表模型和 Compaction 路径:
+
+| 表模型 / 数据路径 | 回收行为 |
+| --- | --- |
+| Duplicate Key | 可在支持的 Segment、Cumulative、Base 和 Full Compaction 路径中回收过期行。 |
+| Unique Key MOW | 可在 Cumulative、Base 和 Full Compaction 中回收已发布 Rowset 
的过期行。发布前的 Segment Compaction 会保留过期 Key,用于写入冲突处理。 |
+| Unique Key MOR | 只有在 Full Compaction,或覆盖从版本 0 开始的历史版本的 Base Compaction 
中才会回收过期行,避免删除后露出同一 Key 的旧版本。 |
+| 冷数据 Compaction | 不执行行级 TTL 回收。 |
+| Changelog Tablet | 不会通过行级 TTL 删除日志条目。原始 Changelog 
中可能仍保留基表已过期行的写入记录,其保留策略独立于行级 TTL。 |
+
+行级 TTL 不保证到期时所有数据副本或变更记录都已被擦除。
+
+<!-- 知识类型: 常见问题 -->
+<!-- 适用场景: 排查 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 值。
+- 
数据天然按整个时间分区保留时,优先考虑[动态分区](../../table-design/data-partitioning/dynamic-partitioning)。行级
 TTL 适合更细粒度的管理,但增加逐行过滤,并限制部分查询优化。
+- 采用前验证实际的导入、更新、查询与 Compaction 工作负载,尤其检查对部分列更新、Sequence 列、物化视图、历史查询和缓存的依赖。
+- 缩短保留时长前确认预期的过期边界,并在此 TTL 
策略之外保留必须可恢复的数据。用普通查询验证可见性,不要把磁盘占用或隐藏列查询当作是否过期、是否彻底擦除的依据。
diff --git a/sidebars.ts b/sidebars.ts
index 6ba053452b73..bd8783b5cdb7 100644
--- a/sidebars.ts
+++ b/sidebars.ts
@@ -510,6 +510,7 @@ const sidebars: SidebarsConfig = {
                     link: {type: 'doc', id: 
'data-operate/delete/delete-overview'},
                     items: [
                         'data-operate/delete/delete-manual',
+                        'data-operate/delete/row-ttl',
                         'data-operate/delete/batch-delete-manual',
                         'data-operate/delete/truncate-manual',
                         'data-operate/delete/atomicity-replace',


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to