bug20251015
为了解决Mysql数据库低版本,没有物化视图 (blog.csdn.net/qq\_3208054… 这两个算法的切换都是开玩笑的破烂手段, 没啥实际上的意义) 相关功能的一种解决手段
传统的clickhouse等相关数据库,都支持物化视图,把视图的数据持久化在本地,免重复查询
“staging + rename”是做物化/快照表的经典手法,在 MySQL 上有明确优势(尤其相对“同表内 delete+insert 再一次性提交”):本质上,都是清空某张表, 然后进行切换的操作
哪些地方更优
- • 原子可见性:
RENAME TABLE在 MySQL 是原子操作。读者要么看到旧表,要么一下子看到新表,不会出现半刷新/空窗。 - • 极小锁定面:构建发生在临时表(staging)上,线上表只在
RENAME的那一瞬间拿 短暂的元数据锁;
而同表DELETE+INSERT虽然放在一个事务里,但会对目标表产生长事务的大量行锁/间隙锁,更容易与线上读写冲突。 - • 更少的脏活累活:
- • 大量
DELETE会生成海量 undo/redo 和 purge 压力,回收很慢,还可能拖慢整体实例。 - •
staging+rename避免对线上表做大DELETE,binlog/redo 压力也更小(依然会记录插入 staging 的日志,但没有“清空线上表”这一步)。
- • 大量
- • 失败更安全:构建失败→直接丢弃 staging,线上表不受影响。
同表DELETE+INSERT若中途异常,虽可回滚,但可能形成长事务、占用大量 undo。 - • 并发友好:staging 期间线上查询完全走旧表,性能稳定;同表方案在大事务期间更容易造成锁等待、统计信息抖动等。
什么时候同表事务也“够用”
- • 数据量很小且明确保证单点串行执行、查询对短时间锁不敏感(但是多业务查询就很敏感此操作了);
- • 不想占用额外磁盘(staging 需要一倍临时空间,但是其实工程里面无所谓)。
这种场景下,同表DELETE+INSERT在一个事务里也能跑通,且实现简单。
staging + rename 的注意点
- • 空间:刷新期间需要≈1×表大小的额外磁盘。
- • 结构一致:
CREATE TABLE ... LIKE mv_table复制索引,但不会复制外键/触发器(若有,需手动补齐)。 - • 统计信息:大表可在 staging 装载后
ANALYZE TABLE staging,切换后查询计划更稳。 - • 并发防抖:用应用层互斥(
GET_LOCK)避免两个刷新任务同时执行。 - • 可观测性:在表里冗余
refresh_time/批次号,便于下游校验是否命中最新快照。
结论
- • 如果你追求更稳的可见性、对线上更小的影响、可失败即弃:staging + rename 更有优势。
- • 若你已评估:数据量小、10 分钟一次、只有单节点触发、能接受短暂的表写锁,那么你现在的同表事务删后插也可以用,只是弹性与容错性不如 staging+rename。
两种方案都不是拍脑袋的;只是工程权衡不同。
.preview-wrapper pre::before { position: absolute; top: 0; right: 0; color: #ccc; text-align: center; font-size: 0.8em; padding: 5px 10px 0; line-height: 15px; height: 15px; font-weight: 600; } .hljs.code__pre > .mac-sign { display: flex; } .code__pre { padding: 0 !important; } .hljs.code__pre code { display: -webkit-box; padding: 0.5em 1em 1em; overflow-x: auto; text-indent: 0; } h2 strong { color: inherit !important; }
本文使用 文章同步助手 同步