bug20251015

28 阅读3分钟

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 避免对线上表做大 DELETEbinlog/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; }

本文使用 文章同步助手 同步