
—— 表级 TTL 自动过期 · TTL 归档到指定表 · 自动日期分区,真机实测与踩坑
继续上次COS特性后,官方升级到了V21.6.4,推出了一些新功能。为了体验这些功能,利用腾讯云的资源开通了TDSQL-B(即TDSQL Boundless)的验证环境。
做数据库运维的可能都经历过订单、日志、审计、埋点这些表,而这些中除了订单数据,其他都是低价值数据,留着占高性能存储,仅仅是偶尔用来查个日志。传统做法是 DBA 人工处理。
TDSQL-B在 V21.6.4 把“数据价值随时间衰减”这件事,直接交给数据库内核去自动完成——分区自动创建、过期自动清理、冷数据自动落对象存储。全程对应用透明:SQL 不改、连接不变、外部调度脚本一套都不用写。这一块是本次发布投入最大、也最容易见效的部分,本实战就聚焦这里。
项目 | 说明 |
|---|---|
实例内核 | 8.0.26.0.0-sqlengine-21.6.4.1(TDSQL Boundless) |
实例标识 | hybrid-0(server_id=64120;SQL 节点 node-tdsql3-kxbig6pevo-001/002) |
存储引擎 | ROCKSDB(LSM-Tree) |
连接方式 | 跳板机 139.199.180.243 → mysql -udbaadmin -h 10.10.0.94 |
对照实例 | 106.55.69.143(21.6.3.0,三项新特性均不可用) |
测试库 | ttl_test |
10多年前我第一次看到TTL这个概念是在Redis和CDH这些产品上。在关系型数据库为主的数据库上不多见。
日志、会话、审计、埋点类表,数据偶尔被查询一下。太久远的数据就没有用了。这种特别适合TTL这种场景。现在只需在建表时声明一行 TTL 表达式,数据库后台分批自动清理,进度可查可审计。
CREATE TABLE app_log ( id BIGINT NOT NULL, created_at DATETIME NOT NULL, content VARCHAR(200), PRIMARY KEY (id)) TTL = created_at + INTERVAL 90 DAY, -- 表达式【不加引号】 TTL_ENABLE = 'ON', TTL_JOB_INTERVAL = '1m'; -- 扫描间隔值需引号 -- 查看 TTL 元数据SELECT SCHEMA_NAME, TABLE_NAME, TTL_ENABLE, TTL_COLUMN, TTL_DURATION, TTL_INTERVAL_TYPE, TTL_JOB_INTERVAL, ARCHIVE_TABLE, ARCHIVE_ON_CONFLICT FROM information_schema.TTL_TABLES WHERE SCHEMA_NAME='ttl_test'\G |
|---|
关键坑 1:TTL 表达式的值不能加引号。最初写成 TTL = 'created_at + INTERVAL 90 DAY'(照搬官方示例的引号),建表直接报 1064。正确写法是 TTL = created_at + INTERVAL 90 DAY,只有 TTL_ENABLE / TTL_JOB_INTERVAL 这类参数值才需要引号。
官方文档说 TTL 列须为日期时间类型,我们专门做了边界验证:
列类型 | 建表结果 | 说明 |
|---|---|---|
DATETIME | ✅ 成功 | 主推类型 |
DATE | ✅ 成功 | 同族,支持 |
TIMESTAMP | ✅ 成功 | 同族,支持 |
VARCHAR | ❌ ERROR 8643 | TTL column must be of type DATE, DATETIME, or TIMESTAMP |
BIGINT | ❌ ERROR 8643 | 整数时间戳不支持,需先转日期类型 |
关键坑 2:很多开发人员为了应用程序处理方便会把时间存成 VARCHAR 或 BIGINT(如 20260920、1738368000)。这两类在 TTL 场景会被直接拒绝,报错 8643。要么改用 DATETIME 列,要么在写入前转换。别指望 TTL 帮你隐式转换——它既不转、也不会静默出错。
TTL 状态可从 information_schema.TTL_TABLES 查询,但列名与直觉略有差异(是 SCHEMA_NAME 而非 TABLE_SCHEMA,是 ARCHIVE_TABLE 而非 TTL_ARCHIVE_TABLE),查询时别写错列名。
*************************** 1. row *************************** SCHEMA_NAME: ttl_test TABLE_NAME: app_log TTL_ENABLE: ON TTL_COLUMN: created_at TTL_DURATION: 90 TTL_INTERVAL_TYPE: DAY TTL_JOB_INTERVAL: 1m ARCHIVE_TABLE: ttl_test.app_log_archiveARCHIVE_ON_CONFLICT: STOP |
|---|
关键坑 3(踩坑实录):TTL 的后台清理/归档依赖全局开关 ttl_enable=ON,默认是关的。我这边 dbaadmin 没有 SUPER 权限,SET GLOBAL 开不了(报 ERROR 1227),所以一开始只能验到建表、语法、视图和类型报错这一层。后来找官方帮忙在后台把 ttl_enable 打开,顺手把调度窗口从默认的 00:00~06:00 调成了 00:00~23:59。再查已经确认:ttl_enable=ON,sys.ttl_task_history 里 app_log 的归档任务也真的跑出了 finished 记录——后台动作这次是真验到了。生产上记得确认开关已开,窗口按业务高峰再定。
“过期就删”有时候太粗暴——审计、合规场景要求数据不能真没,只是从主表挪走。TTL 归档到指定表就是干这个:到期数据先写入归档表、再从原表删除,事务一致,归档表本身还能再落冷。
-- 声明归档目标表ALTER TABLE orders SET TTL_ARCHIVE_TABLE = 'orders_archive'; -- 归档表需满足:显式主键、列是源表超集CREATE TABLE orders_archive ( id BIGINT NOT NULL, created_at DATETIME NOT NULL, content VARCHAR(200), PRIMARY KEY (id)); -- 冲突策略:STOP(默认,遇主键冲突停) / REPLACE(覆盖)-- TTL_ARCHIVE_ON_CONFLICT |
|---|
归档表必须含显式主键,且列集合要覆盖原表(否则归档写入会失败)。
CREATE TABLE ... LIKE 复制表结构时,TTL 定义【不会】跟随——我们实测 dst 表是干净的、不带 TTL。需要归档能力得显式再声明。
官方把 ttl_enable 打开后,归档这次是真的跑起来了:app_log_archive 已落入 2 行(2026-05-23、2026-06-12,都超过 90 天),原表 app_log 同步清理到只剩 2 行窗口内数据,sys.ttl_task_history 里任务 strategy=archive_then_delete、status=finished。开启前那段手动模拟只作语义对齐,真实生产由后台任务执行。
实践建议:归档表和原表建议放在同一 schema;归档表可进一步用上一版冷热分离能力(STORAGE_TIER=OBJECT_STORAGE)落对象存储,做到“主表热、归档冷”的二级降本。
时间序列表(订单、流水、日志)按月/天分区是常识,但传统 RANGE 分区有个老大难:未来分区得人工提前建,建少了写入报“找不到分区”,建多了又浪费。Oracle数据库有这个功能,相比起而言MySQL至今没有这个功能。所有运维起来我经常看到MySQL的同事每到一定月份就要手工增加。而Oracle的运维没有这些事务。而如今V21.6.4 也具备了这样的功能, INTERVAL RANGE 让数据库按指定间隔自动补齐未来分区。
语法要点:INTERVAL 子句紧跟在分区定义之后。日期时间列(DATETIME/DATE/TIMESTAMP)走 RANGE COLUMNS 形式——PARTITION BY RANGE COLUMNS(col) INTERVAL(MONTH, N);整数列(INT/BIGINT)走 RANGE 形式——PARTITION BY RANGE(col) INTERVAL(N)。interval_type 支持 YEAR、QUARTER、MONTH、WEEK、DAY、HOUR、MINUTE、SECOND 共 8 种,N 必须是正整数常量。
-- 日期时间列:RANGE COLUMNS + INTERVAL(MONTH, N)CREATE TABLE m_log (id BIGINT NOT NULL, ts DATETIME NOT NULL, content VARCHAR(100), PRIMARY KEY (id, ts)) PARTITION BY RANGE COLUMNS (ts) INTERVAL (MONTH, 1) ( PARTITION p202601 VALUES LESS THAN ('2026-02-01')); -- 整数列:RANGE + INTERVAL(N)CREATE TABLE m_int (id BIGINT NOT NULL, v BIGINT NOT NULL, content VARCHAR(100), PRIMARY KEY (id, v)) PARTITION BY RANGE (v) INTERVAL (100) (PARTITION p0 VALUES LESS THAN (100)); -- 两种写法均在本实例实测通过,自动建分区结果见下表。 |
|---|
建表时只声明 1 个起始分区 p202601,然后插入三行一路跨到 2027 年 03 月的数据,看系统会不会自动补齐月份分区:
INSERT INTO m_log VALUES (1,'2026-01-15 10:00:00','in p202601'), (2,'2026-09-20 10:00:00','spill -> auto month'), (3,'2027-03-01 10:00:00','far future -> auto month'); SELECT PARTITION_NAME, PARTITION_DESCRIPTION, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA='ttl_test' AND TABLE_NAME='m_log' |
|---|
插入后分区视图(节选):系统按月自动补齐了分区,数据正确落入对应月份:
分区名 | 上界(VALUES LESS THAN) | 行数 |
|---|---|---|
p202601 | '2026-02-01' | 1 ← 2026-01-15 |
_p20261001000000 | '2026-10-01' | 1 ← 2026-09-20 |
…(每月一个,系统自动补齐) | … | … |
_p20270401000000 | '2027-04-01' | 1 ← 2027-03-01 |
实测结论:建表只用 RANGE COLUMNS (ts) INTERVAL (MONTH, 1) 加 1 个起始分区 p202601,插入 2026-01、2026-09、2027-03 三行跨越 14 个月的数据后,系统自动补齐了按月分区——共 15 个(1 个起始 p202601 + 14 个自动创建的 _p202603…_p202704),数据正确落入对应月份。整数列用 INTERVAL(100) 同样自动建出 _p200、_p300、_p400,两种写法都验证通过。整个过程不需要任何外部调度脚本。
下面把本次连环境跑通的完整过程贴出,便于复现。所有 SQL 通过跳板机文件重定向方式执行(多行 SQL 不能用 -e 直传,MariaDB 客户端会破坏分号)。
CREATE TABLE app_log ( id BIGINT NOT NULL, created_at DATETIME NOT NULL, content VARCHAR(200), PRIMARY KEY (id)) TTL = created_at + INTERVAL 90 DAY, TTL_ENABLE='ON', TTL_JOB_INTERVAL='1m';-- Query OK, 0 rows affected ✅ SHOW CREATE TABLE app_log; -- 确认 TTL 已生效 |
|---|
CREATE TABLE t_int (id BIGINT, d BIGINT, PRIMARY KEY(id)) TTL = d + INTERVAL 90 DAY;-- ERROR 8643 (HY000): TTL column 'd' must be of type-- DATE, DATETIME, or TIMESTAMP ❌ 整数时间戳被拒 CREATE TABLE t_date (id BIGINT, d DATE, PRIMARY KEY(id)) TTL = d + INTERVAL 90 DAY;-- Query OK ✅ DATE 同族支持 |
|---|
-- 查看后台 TTL 任务执行情况SELECT task_id, table_name, strategy, status, deleted_rows, finished_at FROM sys.ttl_task_history WHERE table_schema='ttl_test' AND table_name='app_log' ORDER BY task_id DESC LIMIT 3; -- 归档结果核对:SELECT COUNT(*) FROM app_log; -- 2 行(90 天窗口内保留)SELECT COUNT(*) FROM app_log_archive; -- 2 行(超过 90 天,自动迁入) |
|---|
在上一版“冷热分离”基础上,V21.6.4 把能力从“表级手动”细化到“分区级自动”:基于日期分区自动识别冷数据并下发转冷任务,冷数据仍属于原表、仍可用标准 SQL 查询,并具备备份恢复与点查加速。这一项是增强而非全新,但和前面的 TTL / 自动分区天然搭配——自动分区管“切”,自动落冷管“沉”。
-- ① 创建落冷规则:分区键 yyyymm → 时间,超 6 个月落冷CREATE DISTRIBUTION POLICY "auto_cooldown_6m" SET PARTITION_METHOD = "RANGE" AND PARTITION_KEY_TO_TIME_TYPE = ( "sql:STR_TO_DATE(CONCAT(BOUND,'01'),'%Y%m%d')") AND EXPIRE = "6 MONTH" AND STORAGE_TIER = "OBJECT_STORAGE"; -- ② 建分区表并导入数据(官方推荐:先导数,再绑定规则)CREATE TABLE orders ( id BIGINT NOT NULL, yyyymm INT NOT NULL, data VARCHAR(255), PRIMARY KEY (id, yyyymm)) PARTITION BY RANGE (yyyymm) (...); -- ③ 绑定规则,触发分区级自动落冷ALTER TABLE orders USING DISTRIBUTION POLICY "auto_cooldown_6m"; |
|---|
能力 | 解决的真问题 | 真机验证结论 |
|---|---|---|
A 表级 TTL 自动过期 | 日志/会话/审计类表到期自动清理,免手写调度 | ✅ 已真验:官方开启 ttl_enable 后,后台 archive_then_delete 任务跑通,app_log_archive 落 2 行、原表同步清理 |
B TTL 归档到指定表 | 过期数据保留合规,先归档再删、事务一致 | ✅ 已真验:官方开后归档后台执行,过期行迁入归档表、原表清理 |
C 自动日期分区 | 时间序列表未来分区自动补齐,杜绝写入失败 | ✅ 已真验:官方语法 INTERVAL(MONTH, 1) 自动按月建分区,数据正确落位 |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。