MariaDB的SYSTEM VERSIONING无可视化支持,所有操作须用SQL:启用需ALTER TABLE ... WITH SYSTEM VERSIONING,停用会永久删除历史数据,查历史仅支持AS OF语法,备份需手动处理版本定义与分区数据。
System Versioning 表在 MariaDB 里压根没有可视化界面支持
mariadb 的 system versioning 是纯 sql 层特性,服务端不提供任何 web 界面(比如 phpmyadmin、adminer、dbeaver 的表结构页)来开关或编辑版本控制配置。你点开一张带版本控制的表,看到的只是普通字段列表,row_start 和 row_end 字段不会被标记为“系统时间列”,更不会出现“历史版本”标签页。
常见错误现象:
– 在 phpMyAdmin 中修改表结构后,SYSTEM VERSIONING 自动消失
– 用 Adminer 导出再导入,版本定义语句被完全忽略
– DBeaver 的“查看历史”按钮对 versioned 表无响应
- 所有操作必须通过
ALTER TABLE ... WITH SYSTEM VERSIONING或建表时指定WITH SYSTEM VERSIONING - phpMyAdmin 5.2+ 虽能显示
row_start/row_end字段,但不识别其语义,也不阻止你误删它们 - 一旦手动删掉这两个隐藏列(哪怕只是改名),整个版本链就断裂,且不可逆
怎么安全地启用和停用 SYSTEM VERSIONING
启用是原子操作,但停用会丢弃所有历史数据——这点极易被忽略。MariaDB 不保留“停用后还能查历史”的中间状态。
使用场景:上线灰度期想临时关闭版本追踪;迁移旧表到新架构前清理冗余历史
- 启用:
ALTER TABLE users WITH SYSTEM VERSIONING;—— 要求表已有row_start和row_end两个BIGINT或TIMESTAMP(6)列(类型必须匹配) - 停用:
ALTER TABLE users WITHOUT SYSTEM VERSIONING;—— 执行后row_start/row_end变成普通列,历史分区数据(如果用了PARTITION BY SYSTEM_TIME)会被直接 DROP - 不能只改列名来“绕过”版本控制,MariaDB 强制校验列名和类型,
RENAME COLUMN会导致ERROR 4187: Cannot rename system-versioning columns
查历史数据只能靠 AS OF 语法,别指望 GUI 过滤器
phpMyAdmin 的 WHERE 输入框、DBeaver 的“筛选行”功能,对 AS OF 完全无效。你没法在界面上点选“查看 2024-03-15 的用户列表”。
性能影响:AS OF TIMESTAMP 查询会扫描对应时间范围内的所有历史分区(如果用了分区),没索引加速;而普通 SELECT 只走主键
- 正确写法:
SELECT * FROM users AS OF TIMESTAMP '2024-03-15 10:00:00'; - 错误尝试:
SELECT * FROM users WHERE row_start '2024-03-15';—— 这只能查当前有效行,漏掉已删除/更新的历史快照 - 时间精度必须到微秒(
TIMESTAMP(6)),否则AS OF可能返回空结果,即使那个时刻真有数据
备份恢复时 SYSTEM VERSIONING 极易静默失效
mysqldump 默认不导出 WITH SYSTEM VERSIONING 子句,也不备份历史分区数据。恢复后表看起来一样,但实际已退化为普通表。
兼容性注意:MariaDB 10.3.4+ 才支持,低于该版本的 mysqldump 即使连上高版本服务器,也可能漏掉版本相关语法
- 备份必须加参数:
mysqldump --skip-create-options --skip-triggers --no-tablespaces yourdb users,再手动补上WITH SYSTEM VERSIONING - 用
mysqlpump更可靠(MariaDB 10.2.3+),它默认保留SYSTEM VERSIONING定义,但依然不导出历史数据 - 历史数据要单独备份:若用了
PARTITION BY SYSTEM_TIME,需用SELECT ... INTO OUTFILE导出各分区,或停写后FLUSH TABLES WITH READ LOCK+ 文件系统级拷贝.ibd
最麻烦的点在于:失效没有报错,表还能正常增删改,只是“历史”彻底消失了——得靠定期跑 SELECT COUNT(*) FROM users FOR SYSTEM_TIME ALL 来交叉验证是否还有历史记录。










