读书笔记: 数据仓库同步的陷阱与Oracle读一致性的奥秘
我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面浏览效果更佳。
本文为个人学习《Expert Oracle Database Architecture Techniques and Solutions for High Performance and Productivity(第四版本》一书过程中的笔记与理解分享,仅用于学习与交流,部分内容参考原书观点并结合>实际经验进行整理。若涉及版权问题,请联系删除或沟通处理。也请大家支持购买原版书籍。
数据仓库同步的陷阱与Oracle读一致性的奥秘
常见数据仓库同步技术的致命缺陷
许多团队使用以下方法同步数据仓库:
- 在源表使用触发器维护
LAST_UPDATED列 - 初始同步时记录当前时间(如9:00),拉取全量数据
- 刷新时记录新时间(如10:00),拉取9:00后变更的数据
这种方法在支持非阻塞读的数据库(如Oracle)中存在严重问题:如果9:00时有未提交的事务(如8:59:30开始的修改),这些变更既不会出现在9:00的全量拉取中(因为未提交),也不会出现在10:00的增量拉取中(因为修改时间早于9:00)。
解决方案:应该查询V$TRANSACTION视图,获取当前时间和最早活动事务开始时间中的较小值作为同步起点,确保不会遗漏任何变更。
Oracle读一致性的双刃剑
热表I/O异常高的秘密
在生产环境中,某些查询的I/O量可能异常高于测试环境,原因在于Oracle的多版本读一致性机制:
- 当查询需要读取被其他事务修改过的数据块时,必须从撤销段(undo)获取旧版本
- 每个回滚操作都可能涉及额外I/O
- 高并发修改的表会导致查询需要频繁访问撤销段
典型案例:一个简单查询在测试环境只需7次I/O,在生产环境可能激增至10,004次,因为需要回滚10,000次修改才能获取查询开始时的数据版本。
缓冲区缓存的智能优化
Oracle会在内存中保留数据块的多个版本,后续查询可能直接访问缓存中的合适版本,避免重复回滚操作。可以通过查询查看缓存中的块版本数量:
SELECT COUNT(*) FROM v$bh WHERE file#=文件ID AND dbablk=块ID;
通常每个块不超过6个版本,这显著减少了I/O压力。
写一致性的复杂世界
更新操作的双重读取机制
Oracle执行UPDATE时采用两种读取方式:
- 一致读取:查找要修改的行(基于查询开始时的数据快照)
- 当前读取:实际更新行时获取最新块版本
如果发现WHERE条件中使用的列值已被修改,Oracle会重新启动整个更新操作。
令人惊讶的"重新启动"现象
通过触发器可以观察到更新操作的重新启动:
-- 测试表
CREATE TABLE t (x INT PRIMARY KEY, y INT);
INSERT INTO t VALUES (1,5);
-- 观察触发器
CREATE OR REPLACE TRIGGER before_update
BEFORE UPDATE ON t FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('old.x='||:old.x||' old.y='||:old.y);
DBMS_OUTPUT.PUT_LINE('new.x='||:new.x||' new.y='||:new.y);
END;
当两个会话并发更新同一行时,第二个会话的触发器会触发两次,显示出更新被重新启动。
重新启动的深远影响
- 触发器多次执行:可能导致非事务性操作(如发送邮件)重复执行
- 性能问题:大批量更新中途重新启动会导致已处理工作回滚
- PL/SQL变量不一致:重新启动不会回滚PL/SQL全局变量的修改
最佳实践:
- 避免在触发器中执行非事务性操作
- 使用DBMS_JOB等机制在事务提交后执行副作用操作
- 谨慎使用自治事务触发器
- 优先使用AFTER触发器而非BEFORE触发器以提高效率
总结
Oracle的读一致性和多版本控制是强大功能,但也带来独特挑战。理解这些机制对于:
- 设计可靠的数据同步方案
- 诊断性能问题
- 编写正确的数据库应用
至关重要。特别是在高并发环境中,必须考虑长查询与数据修改的交互影响,避免微妙的正确性和性能问题。
------------------作者介绍-----------------------
姓名:黄廷忠
现就职:Oracle中国高级服务团队
曾就职:OceanBase、云和恩墨、东方龙马等
电话、微信、QQ:18081072613
个人博客: (http://www.htz.pw)
CSDN地址: (https://blog.csdn.net/wwwhtzpw)
博客园地址: (https://www.cnblogs.com/www-htz-pw)

浙公网安备 33010602011771号