`

转:commit的异步提交

 
阅读更多

最近有个系统遇到log file sync这个等待事件,找了一些资料,测试了一些方法,下边把异步提交找到的资料发出来。
一直以来ORACLE对于COMMIT默认采取同步写事务LOG的方式,也就是说,一旦发出COMMIT命令,那么必须等待LGWR将事务相关的所有日志信息都已经从LOG BUFFER写出到REDO LOGFILE以后,才会返回发出COMMIT已完成。从10gR2开始,ORACLE推出了一个新的参数COMMIT_WRITE,可以通过调整此参数实现ORACLE在COMMIT时是采用同步或异步日志,该参数有以下值:
1.IMMEDIATE: 发出COMMIT命令后,立即将相关日志信息从LOG BUFFER写出到REDO LOGFILE,也就是每次提交时都必须做一次磁盘I/O操作,默认选项。
2.WAIT:在日志信息从LOG BUFFER写出到REDO LOGFILE的过程中,必须等待LGWR将所有事务相关的所有日志信息都已经从LOG BUFFER写出到REDO LOGFILE以后,才会返回发出COMMIT已完成,默认选项。
3.NOWAIT:发出COMMIT命令后,不管日志信息从LOG BUFFER写出到REDO LOGFILE是否完成,立即返回COMMIT完成。
4.BATCH:ORACLE会对日志信息进行缓冲,ORACLE会按照自己特定的规则将日志信息从LOG BUFFER批量写出到REDO LOGFILE,也就是说,多个I/O操作将打包成一个批次进行处理,以提高性能。
IMMEDIATE和WAIT是传统的提交方式也是默认的提交方式,NOWAIT和BATCH可以说是10gR2的新特性,ORACLE利用此新特性解决在繁忙的系统中LGWR写是数据库瓶颈的问题,当然,同步COMMIT也可以BATCH,异步COMMIT也可以将日志信息立即写出,以上四个参数值可以自由组合,如下:
 
COMMIT_WRITE='{ IMMEDIATE | BATCH } , { WAIT | NOWAIT }'
默认情况是:
 
COMMIT_WRITE=’IMMEDIATE,WAIT’
所以COMMIT_WRITE有下面几种组合:
 
COMMIT_WRITE='IMMEDIATE,WAIT'
COMMIT_WRITE='IMMEDIATE,NOWAIT'
COMMIT_WRITE='BATCH,WAIT'
COMMIT_WRITE='BATCH,NOWAIT'
由于异步COMMIT不能确保事务的相关日志信息已经全部写出到REDO LOGFILE当中,一旦实例崩溃,可能导致已经COMMIT的事务无法恢复,所以一定看程序是否适合使用异步COMMIT,COMMIT_WRITE是动态参数,可以在程序做适合开启异步COMMIT的时候再使用,使用后应在程序不需要使用异步COMMIT的时候尽快关闭异步COMMIT。比如我们的系统,在批量导入条目数据和图片数据的时候,可以开启异步COMMIT特性,在导入数据完成后,关闭异步COMMIT特性,这样可以解决程序在加载数据的时候,大量的LOG FILE SYNC等待事件,即使此时数据库崩溃,可以删除这个批次的数据,重新导入一次。(当然,数据库崩溃的可能不是很大,要不还要我们DBA干嘛)。
下面是我在本机10gR2版本数据库做的简单演示:
 
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
创建测试表T_COMMIT。
 
SQL> create table t_commit (id number, name varchar2(30));
表已创建。
将COMMIT_WRITE参数修改为IMMEDIATE,WAIT,这也是默认值。
 
SQL> alter system set commit_write='immediate,wait';
系统已更改。
向T_COMMIT表中插入10000条数据,没插入一条记录提交一次,记录操作的时间。
 
SQL> begin
  2  for i in 1..10000 loop
  3  insert into t_commit values (i, 'a'||i);
  4  commit;
  5  end loop;
  6  end;
  7  /
PL/SQL 过程已成功完成。
已用时间:  00: 00: 05.67
在COMMIT_WRITE参数修改为IMMEDIATE,WAIT的情况下,向数据库中插入10000条数据需要5.67秒,查看REDO的相关信息。
 
SQL> select * from v$sysstat where statistic# in (90,91,138,140);
STATISTIC#   NAME                 CLASS      VALUE      STAT_ID
----------   ------------------- ------ ----------   ----------
        90   redo synch writes        8      10017   1439995281
        91   redo synch time          8       2671   4215815172
       138   redo writes              2      10027   1948353376
       140   redo write time          2       2131   3094453259
可见,在这种模式下,redo synch writes一万次,redo writes一万次,这就有可能产生 log file sync等待事件,严重影响性能,这也是程序不要修改一条数据就提交一次,建议批量提交的原因。
再测试下COMMIT_WRITE参数的值为IMMEDIATE,NOWAIT模式下,插入10000条记录,也是每插入一条记录就提交一次,记录时间。
 
SQL> alter system set commit_write='immediate,nowait';
系统已更改。
SQL> begin
  2  for i in 1..10000 loop
  3  insert into t_commit values (i, 'a'||i);
  4  commit;
  5  end loop;
  6  end;
  7  /
PL/SQL 过程已成功完成。
已用时间:  00: 00: 01.14
在COMMIT_WRITE参数的值为IMMEDIATE,NOWAIT的情况下,同样插入10000条记录,只用1.14秒,看下REDO的相关信息。
 
SQL> select * from v$sysstat where statistic# in (90, 91, 138, 140);
STATISTIC#   NAME                 CLASS      VALUE      STAT_ID
----------   ------------------- ------ ----------   ----------
        90 redo synch writes          8      10017   1439995281
        91 redo synch time            8       2671   4215815172
       138 redo writes                2      16805   1948353376
       140 redo write time            2       4003   3094453259
可以看到,这次redo synch writes并没有增长,redo writes只增长了6千多次,也就是LOWR只写了6千多次就已经将LOG BUFFER的相关信息写到了REDO LOGFILE,而不是写10000次,还有redo synch time没有发生,而redo write time几乎没有变化,还是2000多毫秒,这种模式需要注意的是,一旦提交完成,而LOWR还没有将所有的REDO BUFFER里面相关的信息写到REDO LOGFILE的时候数据库崩溃,已提交的数据可能会找不回来,这也是这种模式需要慎用的原因。
再测试下COMMIT_WRITE参数的值为BATCH,WAIT模式下,同样插入10000条记录,需要的时间。
 
SQL> alter system set commit_write='batch,wait';
系统已更改。
SQL> begin
  2  for i in 1..10000 loop
  3  insert into t_commit values (i, 'a'||i);
  4  commit;
  5  end loop;
  6  end;
  7  /
PL/SQL 过程已成功完成。
已用时间:  00: 00: 06.20
这次用了6.20秒,竟然比IMMEDIATE,WAIT模式下用了5.67秒的时间还要长,这是由于在COMMIT以后, 客户端需要等待LGWR完成的通知,由于BATCH模式会将其他SESSION的日志信息一起打包批量从LOG BUFFER写入REDO LOGFILE,所以它会查找和等待其他事务的日志信息,再看下BATCH,WAIT模式下LGWR写REDO的相关信息。
 
SQL> select * from v$sysstat where statistic# in (90, 91, 138, 140);
STATISTIC#   NAME                 CLASS      VALUE      STAT_ID
----------   ------------------- ------ ----------   ----------
        90 redo synch writes          8      20023   1439995281
        91 redo synch time            8       6084   4215815172
       138 redo writes                2      26813   1948353376
       140 redo write time            2       6167   3094453259
对照IMMEDIATE,NOWAIT模式的信息可以发现,redo synch writes写了10000次,redo writes也写了10000次,redo write time一直很稳定,还是2000毫秒左右,但是redo synch time却用了3400毫秒左右,从这个实验也可以看出redo synch对性能的影响,这家伙用的时间比redo write用的时间都多。
看下BATCH,NOWAIT模式的效果怎么样。
 
SQL> alter system set commit_write='batch,nowait';
系统已更改。
SQL> begin
  2  for i in 1..10000 loop
  3  insert into t_commit values (i, 'a'||i);
  4  commit;
  5  end loop;
  6  end;
  7  /
PL/SQL 过程已成功完成。
已用时间:  00: 00: 01.01
单SESSION情况下,BATCH,NOWAIT模式和IMMEDIATE,NOWAIT用时差不多,看下LGWR写REDO的相关信息。
SQL> select * from v$sysstat where statistic# in (90, 91, 138, 140);
STATISTIC#   NAME                 CLASS      VALUE      STAT_ID
----------   ------------------- ------ ----------   ----------
        90 redo synch writes          8      20024   1439995281
        91 redo synch time            8       6084   4215815172
       138 redo writes                2      26835   1948353376
       140 redo write time            2       6246   3094453259
看看,这家伙够狠吧,redo synch writes可以说没有发生,redo synch time当然也就没有,redo writes只写了只写了20次左右,redo write time只有几十毫秒,BATCH,NOWAIT将事物的日志信息打包,再由LGWR从LOG BUFFER写到REDO LOGFILE,也就是LOGWR只写了20次左右就写完了提交10000次的日志信息,而且这个时间由以前的2000毫秒降到了几十毫秒,这只是在单SESSION环境下,如果在多SESSION,高并发的环境下,效果会更好一些,可见ORACLE对高并发应用LGWR写瓶颈的改善还是灰常灰常牛X的,但同样值得关注的还是高性能带来的高风险,还好COMMIT_WRITE是动态参数,可以随意调整而不需要重启数据库,这也是我在考虑我们的应用是否使用COMMIT_WRITE参数的原因。
还是看下BATCH模式对高并发环境LGWR写REDO的信息,为了演示更直观,本实验使用BATCH,WAIT模式,而且重启了数据库,清空v$sysstat视图的信息,本实验一共开了5个SESSION,每个SESSION都执行上述实验的SQL,都插入10000条记录,看下LGWR写REDO的信息。
SQL> alter system set commit_write='batch,nowait';
系统已更改。
5个SESSION都同时执行下面的SQL,每个SESSION都插入10000条记录。
 
SQL> begin
  2  for i in 1..10000 loop
  3  insert into t_commit values (i, 'a'||i);
  4  commit;
  5  end loop;
  6  end;
  7  /
PL/SQL 过程已成功完成。
然后查看LGWR写REDO的信息。
 
SQL> select * from v$sysstat where statistic# in (90, 91, 138, 140);
STATISTIC#   NAME                 CLASS      VALUE      STAT_ID
----------   ------------------- ------ ----------   ----------
        90 redo synch writes          8      50010   1439995281
        91 redo synch time            8      52530   4215815172
       138 redo writes                2      19336   1948353376
       140 redo write time            2       8747   3094453259
5个SESSION都插入10000条数据,redo synch writes5万次, redo synch time高达52530毫秒,但redo writes并不是5万次,而是19336次,这是由于BATCH将其他SESSION的日志信息打包处理了。
如果是BATCH,NOWAIT模式,这个结果让我很震惊,也让我想起了2011年的经典台词,至于你信吗?反正我信了!下面是重启数据库后,BATCH,NOWAIT模式下5个SESSION同时插入10000条数据的LGWR写REDO日志的信息。
 
SQL> select * from v$sysstat where statistic# in (90, 91, 138, 140);
STATISTIC#   NAME                 CLASS      VALUE      STAT_ID
----------   ------------------- ------ ----------   ----------
        90 redo synch writes          8          6   1439995281
        91 redo synch time            8          2   4215815172
       138 redo writes                2         68   1948353376
       140 redo write time            2        489   3094453259
redo synch writes只有6次,还可能不是由于插入数据产生的,可能是ORACLE内部的调用引起的,redo writes只有68次,就写完了所有的日志信息,而且只用了489毫秒!震撼吗?
COMMIT_WRITE是10gR2引入的新特性,11g版本的数据库已经不在使用COMMIT_WRITE参数,11g使用COMMIT_WAIT和COMMIT_LOGGING取替了COMMIT_WRITE参数,如果在11g的数据库中设置了COMMIT_WRITE参数,重启后,将会报ORA-32004错误。
 
SQL> alter system set commit_write=immediate,nowait;
系统已更改。
SQL> shutdown immediate
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> startup
ORA-32004: obsolete or deprecated parameter(s) specified 
for RDBMS instance
ORACLE 例程已经启动。
Total System Global Area  313860096 bytes
Fixed Size                  1374304 bytes
Variable Size             239077280 bytes
Database Buffers           67108864 bytes
Redo Buffers                6299648 bytes
数据库装载完毕。
数据库已经打开。
ORACLE会说这是个老掉牙的参数了,我现在已经不用了,你设置这个参数就相当于在参数文件里写了一条垃圾,我根本不用它,但是这个错误不影响数据库的启动和运行。
被COMMIT_LOGGING和COMMIT_WAIT取代的COMMIT_WRITE参数在11g有所增强,COMMIT_LOGGING参数有IMMEDIATE和BATCH两个值可选,COMMIT_WAIT参数有WAIT、NOWAIT和FORCE_WAIT三个值可以选择,ORACLE的馆方文档说COMMIT_LOGGING和COMMIT_WAIT没有默认值,是说SQLPLUS里看不到默认值,实际上ORACLE的COMMIT机制默认是IMMEDIATE和FORCE_WAIT。
 
SQL> show parameter commit_
NAME                       TYPE                VALUE
------------------------   -----------------   --------
commit_logging             string
commit_point_strength      integer             1
commit_wait                string
commit_write               string
关于11g关于这方面的性能测试不再演示,摘录下11g官方文档有关参数的介绍:
 
这部分主要对COMMIT_LOGGING参数的简单介绍,主要说COMMIT_LOGGING是个新引进的参数,有IMMEDIATE和BATCH两个值可以选择,可以在会话级和系统级进行设置,RAC的每个节点都可以单独设置,还说如果在COMMIT_WAIT参数设置FORCE_WAIT之后修改COMMIT_LOGGING参数,那么FORCE_WAIT将失效。
 
COMMIT_WAIT is an advanced parameter used to control when the redo for a commit is flushed to the redo logs.
Be aware that the NOWAIT option can cause a failure that occurs after the database receives the commit message, but before the redo log records are written. This can falsely indicate to a transaction that its changes are persistent. Also, it can violate the durability of ACID (Atomicity, Consistency, Isolation, Durability) transactions if the database shuts down unexpectedly.
If the parameter is set to FORCE_WAIT, the default behavior (immediate flushing of the redo log buffer with wait) is used. If this is a system setting, the session level and transaction level (COMMIT_WRITE) options will be ignored. If this is a session level setting, the transaction level options will be ignored. If COMMIT_WAIT is altered after it has been set to FORCE_WAIT, then the FORCE_WAIT option is no longer valid.
一样,这部分也是对COMMIT_WAIT参数的简单介绍,主要说COMMIT_WAIT参数有WAIT、NOWAIT和FORCE_WAIT三个值可以选择,可以在会话级和系统级做设置,RAC的每个节点都可以单独设置,还说了下NOWAIT可能会由于虚假提交丢失数据。
 
COMMIT_WRITE is an advanced parameter used to control how redo for transaction commits is written to the redo logs. The IMMEDIATE and BATCH options control how redo is batched by Log Writer. The WAIT and NOWAIT options control when the redo for a commit is flushed to the redo logs.
Note:
The COMMIT_WRITE parameter is deprecated. It is retained for backward compatibility only. It is replaced by the COMMIT_LOGGING and COMMIT_WAIT parameters.
这部分是对COMMIT_WRITE参数的简单介绍,主要是说COMMIT_WRITE是个过度参数,在11g已经被COMMIT_LOGGING参数和COMMIT_WAIT参数所取代。

 

 

原创http://blog.itpub.net/29523859/viewspace-1331176/

分享到:
评论

相关推荐

    vuex中store存储store.commit和store.dispatch的用法

    代码示例: this.$store.commit(‘loginStatus’, 1); this.$store.dispatch(‘isLogin’, true);...dispatch:含有异步操作,数据提交至 actions ,可用于向后台提交数据 写法示例: this.$store

    last-commit-log:Node.js模块获取最新的git commit信息-主要由CICD和构建阶段使用

    最后提交日志 Node.js模块可获取最新的git commit信息-主要由CI / CD和构建阶段使用。谁在用 :star: :star: :star: :star: :star: :star: :star: :star: :star:用法 const LCL = require ( 'last-commit-log' ) ;...

    promise-tutorial:JavaScript异步和Promise教程

    测试异步JavaScript 这是有关测试异步JavaScript的教程贡献克隆此仓库。 npm install npm start 在浏览器中编辑提交拉取请求这将启动TiddlyWiki服务器。 在浏览器中打开http://localhost:8080并进行编辑。 它们会...

    ABAP 函数介绍

    这条语句将异步调用 ZSD_ZK03 函数模块,并在 Commit Work 语句执行后执行。 1.1 本地异步调用 本地异步调用是指在同一个应用服务器上异步调用函数模块。这种方式可以提高系统的性能和效率,特别是在需要长时间...

    commit-watch:确保根据您的commitlint配置格式化提交消息

    提交观察 概述 CommitWatch检查提交消息,并确保它们符合。 入门 您可以从npm安装dev commit-watch软件包作为dev依赖项: npm i --save-dev commit-watch 或者 yarn add -d commit-watch 或者只是通过npx commit-...

    MySQL关于异步复制、同步复制半同步复制、无损复制的概念与区别

    同步复制(Synchronous Replication)要求在事务提交到主服务器的存储引擎并且返回给客户端commit成功的状态之前,必须确保该事务已经被所有从服务器接收并应用。在MySQL中,这通常是通过在事务提交后等待所有从...

    async-websocket:异步WebSocket客户端和服务器,支持Ruby的HTTP1和HTTP2

    提交更改( git commit -am 'Add some feature' ) 推送到分支( git push origin my-new-feature ) 创建新的拉取请求 执照 根据MIT许可证发布。 版权所有,2015。 特此免费授予获得该软件和

    RocketMQ概念 producer:生产者,消息发送者

    - **PushConsumer**:内部异步拉取消息,自动提交offset,适合并发消费。 - **SimpleConsumer**:用户需主动拉取消息和提交消费结果,适合手动控制。 - **PullConsumer**:官方未详细说明,可能是用户主动拉取...

    Tools-Android-Client:Proxy Commit Android Client(代理提交Android客户端)

    "Tools-Android-Client"是一个专门针对Android平台的工具,主要功能是实现“代理提交”功能,即Proxy Commit Android Client。这个工具的核心在于提供一种机制,使得Android客户端可以通过代理服务器来提交数据或...

    我们喜欢的 10 个 Oracle 数据库 10g 第 2 版特性

    - **命令语法**:使用`COMMIT WORK WRITE BATCH NOWAIT`命令进行异步提交。 - **适用场景**:虽然异步提交非常适合数据加载应用,但对于在线事务处理(OLTP)系统来说可能并不合适,因为这可能会增加数据不一致的...

    :collision::collision:快速锈蚀的git的快速终端用户界面:crab:-Rust开发

    用于Rust编写的Git的Terminal-UI面向用于Rust编写的git的快速终端客户端快速而直观的键盘仅可控制基于上下文的帮助(无需记住大量的热键)检查,提交和修改更改(包括钩子): commit-msg / post-commit)暂存,取消...

    《SPT指令集》.docx

    异步提交一个事务。 - `nConnectionHandle`:连接句柄。 **返回值:** - 1:执行成功。 - -1:出现连接层错误。 - -2:出现环境层错误。 ##### 13. SQLROLLBACK **功能描述:** 异步取消当前事务处理过程中所做的...

    用 rust 编写的用于 git 的快速终端用户界面 :collision:

    特征快速直观的仅键盘控制基于上下文的帮助(无需记住大量热键)检查、提交和修改更改(包括钩子:commit-msg /post-commit )暂存、取消暂存、还原和重置文件和大块头存储(保存、应用、删除和检查)推送到远程分支...

    andorid_Sp_提交后数据缺失的问题

    总的来说,处理Android SP提交后数据缺失的问题,需要理解Android进程管理、SP的特性以及如何在程序设计中引入健壮性。通过选择适当的保存策略和恢复机制,可以有效减少因进程被杀导致的数据丢失。

    ExtJs4.1 treegrid CRUD 读取、新增、修改、删除

    实现treegrid组件的(CRUD)读取、新增、修改、删除 //设置grid单元格处于编辑状态 ...//异步Ajax提交新增数据 insertdb:function(newrecords) //异步Ajax提交修改数据 updatedb:function(updaterecords)

    c# Dapper,添加,修改,删除,查询,事务,存储过程,含数据库

    - `Commit`和`Rollback`: 事务提交和回滚,当所有操作成功时提交,有错误时回滚,确保数据的一致性。 6. **Dapper的存储过程调用**: - `Query<T>`配合`CommandType.StoredProcedure`:调用存储过程并获取结果集...

    git-log-as-object:以JavaScript对象的形式获取任何提交范围的历史记录

    :选项):Promise <Commit> 异步获取特定参考范围内所有提交的元数据。参数options :包含函数可选参数的对象。 请参见下面的“选项参数”。返回一个承诺对象数组的承诺,其中包含范围内每个提交的元数据。 (请...

    数据库sql2005转换成sql2000的生成脚本

    - **CURSOR_CLOSE_ON_COMMIT OFF**:关闭游标提交时关闭行为。 - **CURSOR_DEFAULT GLOBAL**:设置全局默认游标行为。 - **CONCAT_NULL_YIELDS_NULL OFF**:关闭NULL拼接行为。 - **NUMERIC_ROUNDABORT OFF**:关闭...

    vuex 解决报错this.$store.commit is not a function的方法

    这样,当点击按钮时,`newBankName` 方法会被调用,通过 `this.$store.commit` 提交 mutation,改变 store 中的 `bankInf.bankName`。 总的来说,Vuex 提供了 state(状态)、mutations(状态变更函数)、actions...

Global site tag (gtag.js) - Google Analytics