在不真正更改数据的情况下发出多个提交时的性能影响
Posted
技术标签:
【中文标题】在不真正更改数据的情况下发出多个提交时的性能影响【英文标题】:Performance impact when issuing multiple commits without really changing the data 【发布时间】:2014-03-03 04:39:09 【问题描述】:我们有一个系统访问 Oracle 11.g 底层数据库。
作为处理流程的一部分,我们有大约 60 个进程不断轮询数据库以每 10 毫秒查找要处理的消息。
每个处理器在 PROCESSORS 表中都有对应的行(PROCESSOR_ID NUMBER,MESSAGGE_ID NUMBER)
如果为给定处理器找到要处理的消息,它将更新该处理器的 MESSAGE_ID 列。 如果没有要处理的内容,它将使用空值更新 MESSAGE_ID。使用我们当前的实现,即使 MESSAGE_ID 的当前值为 null,它仍会将 MESSAGE_ID 更新为 null。用 null 更新 null 是 90% 的时间发生的事情。
轮询过程发生在容器管理事务 (CMT) 中。
所以我们有很多虚假的(用 null 更新的 null)更新,然后是提交。
60 个处理器 x 3600 秒/小时 x 100 更新/秒 = 21600000 次提交/小时
实际上,它们大约是 1600 万次交易/小时,因为当找到要处理的东西时,需要更多时间才能再次寻找工作。
理想情况下,如果没有任何变化,我们应该更改系统而不更新 PROCESSORS 条目,我们肯定会这样做。然而,轮询过程的事务行为不在我们的控制范围内(容器和第三方工作流产品为我们做这件事),所以无论我们是否更新该记录,它仍然会有很多提交。
所以我的问题是:您是否认为这个“不更新任何内容”然后提交会对系统产生性能影响,如果是,您是否认为删除“不更新任何内容”会改善它。
我提出问题的原因是,就在发布前几天,作为我们性能运行的一部分,我们发现系统运行正常大约十个小时,然后突然不知从哪里开始表现非常糟糕。
提前致谢
【问题讨论】:
【参考方案1】:提交肯定是数据库的开销,提交会消耗额外的资源并且运行速度较慢。在某些情况下,它也可能导致数据完整性问题。
事实上,你应该只在事务完成时触发提交,当根本没有事务时,为什么要给数据库增加额外的负担?
更重要的是,您可以在 Tom Kyte 的 very good article 中探索更多内容。 The link 会帮助你更清楚地理解。
【讨论】:
【参考方案2】:删除“不更新”将显着提高性能。将列更新为相同的值与更新为不同的值一样昂贵。下面的简单测试用例显示了在删除不必要的更新后有了显着的改进。
drop table processors;
create table PROCESSORS
(
PROCESSOR_ID NUMBER primary key,
MESSAGE_ID NUMBER
);
insert into processors
select level, null
from dual connect by level <= 100;
commit;
begin
for i in 1 .. 100000 loop
update processors set message_id = null where processor_id = 1;
commit;
end loop;
end;
/
begin
for i in 1 .. 100000 loop
--update processors set message_id = null where processor_id = 1;
commit;
end loop;
end;
/
在我的桌面上删除 update
将运行时间从 8.5 秒提高到 1.3 秒。
您可能还想留意一些weird performance issues when updating the last column to null。删除无意义的更新后,可能值得切换列顺序,以便更新的列在前,以避免堆块压缩等待。但在你知道它正在发生之前,我不会针对这个问题进行优化。
【讨论】:
我原以为 Oracle 会足够聪明地计算出,当我用相同的值更新给定字段时(通过应用一些非常对数据进行快速 MD5 算法并意识到没有任何变化,甚至不费心将该块标记为脏并为“假更新”创建重做日志条目。看起来我的假设是错误的,所以我别无选择,只能避免冗余更新。嗯……我的老板不会对发布延迟感到满意,但延迟发布比紧急发布要好。 使用 MD5 算法会产生额外的成本,而且不安全,仍然有误报的可能。另外你为什么不修改更新语句以确保值确实改变了?以上是关于在不真正更改数据的情况下发出多个提交时的性能影响的主要内容,如果未能解决你的问题,请参考以下文章
如何在不影响密码更改行为的情况下正确防止 ASP.NET Identity 2.2.1 中的多个活动会话?
如何在不影响未分阶段更改的情况下丢弃 git 中的分阶段更改 [重复]