分类目录归档:转载文章(档)

Oracle ORA-01555快照过旧的错误(转载)

转载地址:http://blog.csdn.net/liaoyuanzi/article/details/7712682

关于Oracle ORA-01555快照过旧的错误


首先了解Oracle在什么情况下会产生ORA-01555错误: 


假设有一张6000万行数据的testdb表,预计testdb全表扫描1次需要2个小时,参考过程如下: 


1、在1点钟,用户A发出了select * from testdb;此时不管将来testdb怎么变化,正确的结果应该是用户A会看到在1点钟这个时刻的内容。


2、在1点30分,用户B执行了update命令,更新了testdb表中的第4100万行的这条记录,这时,用户A的全表扫描还没有到达第4100万条。毫无疑问,这个时候,第4100万行的这条记录是被写入了回滚段,假设是回滚段UNDOTS1,如果用户A的全表扫描到达了第4100万行,是应该会正确的从回滚段UNDOTS1中读取出1点钟时刻的内容的。 


3、这时,用户B将他刚才做的操作提交了,但是这时,系统仍然可以给用户A提供正确的数据,为那第4100万行记录的内容仍然还在回滚段UNDOTS1里,系统可以根据SCN到回滚段里找到正确的数据,但要注意到,这时记录在UNDOTS1里的第4100万行记录已经发生了重大的改变:就是第4100万行在回滚段UNDOTS1里的数据有可能随时被覆盖掉,为这条记录已经被提交了! 


4、由于用户A的查询时间漫长,而业务在一直不断的进行,UNDOTS1回滚段在被多个不同的transaction使用着,这个回滚段里的extent循环到了第4100万行数据所在的extent,由于这条记录已经被标记提交了,所以这个extent是可以被其他transaction覆盖掉的! 


5、到了1点45分,用户A的查询终于到了第4100万行,而这时已经出现了第4条说的情况,需要到回滚段UNDOTS1去找数据,但是已经被覆盖掉了,这时就出现了ORA-01555错误。 以上此段非本人原创 


 


分析:"报表"程序执行时间漫长,在程序查询的过程中其他用户对"报表"进行了更新,被更新的数据写入了回滚段,当程序到回滚段找数据时,发现数据已经被覆盖掉,于是就出现了ORA-01555错误。另外"报表"程序执行效率不高也会造成ORA-01555错误。
解决办法:
1、扩大回滚段,为回滚段是循环使用的,如果回滚段足够大,那么那些被提交的数据就能保存足够长的时间,使那些大事务完成一致性读取。之前EBS系统UNDO表空间为9GB,目前为10GB。见下图:



2、增加undo_retention时间,为UNDO回滚段是循环使用,里面的数据可能随时被循环覆盖掉,如果设置undo_retention时间更长,那么在retention规定的时间内,任何其他事务都不能覆盖这些数据。目前EBS系统undo_retention为10800秒(3个小时)。见下图:
 


3、最重要的一点就是优化程序相关查询语句,减少查询语句的一致性读,降低读取不到回滚段数据的风险。所有的出错信息都会纪录到数据库日志alert_PROD.log文件中,下图红线部分是一条SQL查询词句,ORA-01555很有可能是这条语句造成,把这条语句提供给开发人员来分析和优化程序代码。


————————————————————————————————————————–

ORA-01555 原与解决:

前面提到了ORA-01555错误,那么现在来看一下ORA-01555错误是怎样产生的。由于回滚段是循环使用的,当事务提交以后,该事务占用的回滚段事务会被标记为非活动,回滚段空间可以被覆盖重用。那么一个问题就出现了,如果一个查询需要使用被覆盖的回滚段构造前镜像实现一致性读,那么此时就会出现Oracle著名的ORA-01555错误。

ORA-01555错误的另外一个原为延迟块清除(Delayed Block Cleanout)。当一个查询触发延迟块清除时,Oracle需要去查询回滚段获得该事务的提交SCN,如果事务的前镜像信息已经被覆盖,并且查询SCN也小于回滚段中记录的最小提交SCN,那么Oracle将无从判断查询SCN和事务提交SCN的大小,此时出现延迟块清除导致的ORA-01555错误。

另外一种导致ORA-01555错误的情况出现在使用sqlldr直接方式加载(direct=true)数据时。当通过sqlldr direct=true 方式加载数据时,由于不产生重做和回滚信息,Oracle直接指定Cached Commit SCN 给加载数据,在访问这些数据时,有时会产生ORA-01555错误。

看下图的描述:假定在时间T用户A发出一条更新语句,更新SCOTT用户的SAL;用户B在Ty时间发出查询语句,查询SCOTT用户的SAL;用户A的更新在Tx时间提交,提交可能为快速提交块清除,也可能是延迟块清除;用户B的查询在Tz时间输出。

来看一下数据库在不同情况下的内部处理:

如果 Ty < T < Tz < Tx ,那么查询需要构造一致性读,由于事务尚未提交,可以通过回滚段构造前镜像,完成一致性读取。
·如果 Ty < T < Tx < Tz ,由于Ty查询时间小于T事务更新时间,那么数据库需要构造一致性读取,而Tz查询完成时间大于Tx提交时间,那么前镜像就有可能被覆盖,不可获取。

如果Tx的提交方式为Fast Block Cleanout,那么回滚段信息不可用时就会出现一致性读ORA-01555错误。

如果Tx的提交方式为Delayed Block Cleanout,那么回滚段信息不可用时Oracle将无法判断Ty和Tx的时间先后关系。如果 Ty > Tx ,那么Oracle可以正常进行块清除,并将块清除后的数据返回给用户B;如果 Ty < T ,那么Oracle需要继续构造一致性读返回给用户B;Oracle无法判断这两种情况,就会出现延迟块清除ORA-01555错误。

ORA-01555的直观解释是“snapshot too old”,也就是快照太旧,其根本含义就是查询需要的前镜像过于“久远”,已经无法找到了。可以想象,如果一个历时数个小时或十几个小时的查询,如果最后遭遇ORA-01555错误而失败,会是多么令人沮丧的一件事。一直以来,ORA-01555都是ORACLE最为头痛的问题之一。

在Oracle 9i的文档中这样描述ORA-01555错误:

01555, 00000, "snapshot too old: rollback segment number %s with name \"%s\" too small"
// *Cause: rollback records needed by a reader for consistent read are
//         overwritten by other writers
// *Action: If in Automatic Undo Management mode, increase undo_retention
//          setting. Otherwise, use larger rollback segments

可以看到,在Oracle 9i自动管理UNDO表空间模式下,UNDO_RETENTION参数的引入正是为了减少ORA-01555错误的出现。这个参数设置当事务提交之后(回滚段变得非活跃),回滚段中的前镜像数据在被覆盖前保留的时间,该参数以秒为单位,9iR1初始值为900秒,在Oracle 9iR2增加为10800秒。

显然该参数设置的越高就越能减少ORA-01555错误的出现,但是保留时间和存储空间是紧密相关的,如果UNDO表空间的存储空间有限,那么Oracle就会选择回收已提交事务占用的空间,置UNDO_RETENTION参数于不顾。

在Oracle 9i的AUM模式下,UNDO_RETENTION实际上是一个非担保(NO Guaranteed)限制。也就是说,如果有其他事务需要回滚空间,而空间出现不足时,这些信息仍然会被覆盖;从Oracle 10g开始,Oracle对于UNDO增加了Guarantee控制,也就是说,可以指定UNDO表空间必须满足UNDO_RETENTION的限制。当UNDO表空间设置为Guarantee,那么提交事务的回滚空间必须被保留足够的时间,如果UNDO表空间的空间不足,那么新的事务会空间不足而失败,而不是选择之前的覆盖。

从各个不同版本回滚段的管理变迁,我们可以看出Oracle一直在进步。

Oracle提供了一个内部事件(10203事件)可以用来跟踪数据库的块清除操作,10203事件可以通过以下命令设置,设置后需要重新启动数据库该参数方能生效:


 

alter system set event="10203 trace name context forever" scope=spfile;


 

需要注意的是,可能存在另外一种情况,就是当执行延迟块清除时,回滚段或原回滚表空间已经被删除,此时Oracle仍然可以通过字典表UNDO$来获得SCN信息,执行块清除。

关于Oracle的提交处理及块清除机制是一个极其复杂的过程,本文对这部分内容进行了适当简化说明,旨在使大家能够对Oracle的回滚机制、块清除机制有所了解。

– The End –

NVARCHAR 和VARCHAR区别和使用

1、各自的定义:

       ► nvarchar(n):包含n个字符的可变长度Unicode字符数据。n的值必须介于1与4,000之间。字节的存储大小是所输入字符个数的两倍。所输入的数据字符长度可以为零。 

       ► varchar[(n)]:长度为n个字节的可变长度且非Unicode的字符数据。n 必须是一个介于1和8,000之间的数值。存储大小为输入数据的字节的实际长度,而不是n个字节。所输入的数据字符长度可以为零。

varchar(max)最大2gb字符 使用C#中的DbType.varchar针对max DbType.varchar,-1

2、区别:

      ► 从存储方式上,nvarchar是按字符存储的,而 varchar是按字节存储的;

      ► 从存储量上考虑,varchar比较节省空间,因为存储大小为字节的实际长度,而 nvarchar是双字节存储;

      ► 在使用上,如果存储内容都是英文字符而没有汉字等其他语言符号,建议使用varchar;含有汉字的使用nvarchar,因为nvarchar是使用Unicode编码,即统一的字符编码标准,会减少乱码的出现几率;

      ►如果你做的项目可能涉及不同语言之间的转换,建议用nvarchar。

这点要注意:varchar适合与存储英文和数字;nvarchr一般用于存储中文或其他语言的输入,因为这样,可以防止到其他语言平台上出现乱码的问题。

举个例子: 
create table a (name1 varchar(8)) 
insert a select '张红a' 
–存储长度为5个字节 
insert a select '王一南' 
–存储长度为6个字节

–意思是varchar变长字符数据类型与存储数据的实际长度是一致的 

nvarchar(n):可变长度 Unicode 数据,其最大长度为 4,000 字符。 
字节的存储大小是所输入字符个数的两倍, 
就是说它是双字节来存储数据的。 
如果存储数据如果存在单字节时,它也是以双字节来占用存储空间的。 

举个例子: 
create table aa (name1 nvarchar(8)) 
insert aa select '张红a' 
–存储长度为6个字节

摘自:http://blog.csdn.net/feixianxxx/article/details/4454659

资金检查

  这两天一直在看资金检查的问题,在网上看到一篇文章,觉得写得挺好,加上自己的一下见解并转载。转载地址:http://hi.erp100.com/space-101090-do-blog-id-13563425.html
  在资金检查的时候,需要用到的记张表:
  1、gl_bc_packets
  2、gl_bc_packet_arrival_order
  3、gl_balances

  启用保留款控制后GL、AP、PO的业务会在gl_bc_packets和gl_bc_packet_arrival_order中插入实际、预算和保留款的记录
一、 总帐
  1、资金检查
  每次检查资金产生一个新的PACKET_ID,余额类型为’A’–实际余额,在gl_bc_packets中为凭证批中的每一凭证行插一行记录,其中FUNDS_CHECK_LEVEL_CODE为’N’表示不要进行资金检查;’Y’表示要求进行资金检查,
  检查状态在STATUS_CODE中反映:’S’表示通过检查;’R’表示已拒绝,在gl_bc_packet_arrival_order中为每一凭证批插入记录,对于资金检查affect_funds_flag标志为’N’

  2、保留资金
  每次保留资金产生一个新的PACKET_ID
  保留资金时在2个表中插入记录,非保留资金时删除记录
  其中gl_bc_packets中STATUS_CODE为’A’表示已审批;
  gl_bc_packet_arrival_order中affect_funds_flag标志为’Y’

  3、凭证过账
  凭证过账后将gl_bc_packets中和该凭证相关的的所有记录删除
  同时系统更新gl_balances表的实际余额
  注意:如果将凭证删除则gl_bc_packets中仍将保留资金检查产生的相关记录

二、 应付

  在应付模块中只对发票分配行进行控制

  1、发票审批后产生
  借:帐户(E类型)
  在gl_bc_packets插入1条记录
  该保留类型凭证需提交创建日记帐请求来产生

  2、ap发票过账后产生
  贷:帐户(E类型)
  借:帐户(A类型)
  贷:负债帐户(A类型)
  在gl_bc_packets插入以上3条记录,同时总账产生实际和保留类型的凭证

  3、当实际和保留类型的凭证在总账过账后gl_bc_packets的4条记录自动删除同时系统更新gl_balances表的实际和保留余额

三、采购

  1、采购审批产生保留款
  在gl_bc_packets插入1条记录,对费用类采购保留款帐户一般为输入的费用帐户,对库存类采购一般为item上的保留款帐户,具体请参照workflow中的定义。
  该保留款凭证需在总帐提交创建日记帐请求来产生。

  2、发票匹配审批后
   2.1对费用类采购:冲销采购保留、产生发票保留
   在gl_bc_packets插入2条记录(无发票采购价格差异时)
   有价格差异时还将产生价格差异行,一般为采购单上输入的费用帐户
   借:帐户(E类型)—发票保留订单价
   贷:帐户(E类型)—采购保留订单价
   借/贷:帐户(E类型)—发票保留IPV
   该保留类型凭证需提交创建日记帐请求来产生

   2.2对库存类采购:
    2.2.1采购接收时
    在gl_bc_packets中插入实际余额的相关记录
    借:商品采购(A类型)
    贷:应计负债(A类型)
   
    2.2.2入库
    库存类采购只有当物品入库并传送总账时才产生凭证冲销采购保留,gl_bc_packets中并无任何相关记录
    借:库存(A类型)
    库存帐户可通过workfolow定义,一般可从ITEM,子库存,库存组织中获取(标准成本下)
    贷:商品采购(A类型)
    贷:采购保留订单价(E类型)

    2.2.3发票匹配
    产生IPV差异的发票保留款,一般为组织参数中的相关帐户
    借/贷:帐户(E类型)—发票保留IPV
    注意:冲销采购保留仅和入库数量相关,和发票无关

  3、发票过账产生实际、冲销发票保留
   在gl_bc_packets插入记录
   借:应计负债或订单费用帐户(A类型)订单价
   贷:应付帐款(A类型)发票价
   借/贷:差异帐户(A类型)IPV——从查询发票分配可查出
   贷:帐户(E类型)—发票保留订单价(仅对费用类采购)
   借/贷:帐户(E类型)—发票保留IPV

  4、发票付款
   在gl_bc_packets插入记录
   借:应付帐款(A类型)发票价
   贷:现金/银行(A类型)发票价

  5、总账凭证过账
   gl_bc_packets中的记录被删除
   总结:在凭证过账前系统从gl_bc_packets 和gl_bc_packet_arrival_order中检查可用资金,凭证过账后从gl_balances中检查可用资金。

  实施注意事项:
  1、 打开会计期要注意:当启用保留款会计之前审批的业务将无法产生保留凭证,而它们在此后所发生的业务将采用保留控制,这将产生差异。因此,最好在年初或月初启用保留款。当发生差异时可在月底关帐后对未结业务进行处理,即请购单、采购单、发票、接收及入库。由于保留款最终将转为实际余额,所以将所有可能产生保留款凭证的业务处理完毕后,通过在总账输入保留款调整凭证,可将保留款调整为零。
  2、 系统只能对帐户余额进行控制,而不能控制借方发生或贷方发生数。
  3、对库存类采购为确保对库存材料的控制,要求采购单上的到货期(GL_DATE)需和实际接收入库期尽量一致。这样才能保证正确的冲销采购保留,产生实际发生。
  4、要对材料采购作预算控制,必须在应付模块的财务选项启用“使用PO保留选项”,材料采购分为两种,费用类采购和库存类采购,对于费用类采购,预算的控制帐户直接是采购订单的借计帐户,对于库存类采购,预算控制帐户首先会取子库存设置的保留款帐户,如果子库存层没有,则取Item的保留款帐户,接着取库存组织参数的保留款帐户,你可以去测试一下。
  5、在这种情况下,无法通过对部门进行明细预算,只能通过汇总模板对预算科目进行汇总控制!
 
  Oracle把预算分为:
  1、预算金额:即你实际制定的预算额
  2、实际已经发生金额:即你实际生成总帐分录的金额
  3、预算保留额:即未实际生成总帐分录,但已经有PR、PO或AP发票,此时就会生成保留款
  4、预算可用额:可用额 = 预算金额 - 实际已经发生额 -预算保留额

  当本次预算发生时,是通过本次发生额跟预算可用额进行判断的。
  本次发生额 <可用额,则预算直接通过
  本次发生额 >可用额,则会进行预算的分级控制,级别控制分三种:无控制、警告和完全控制

 最后附上资金研究所用到的几个程序包:
  Funds Check Errors With PSA_BC_XLA_PUB.BUDGETARY_CONTROL (文档 ID 469018.1)
  PSA_BC_XLA_PUB
  GL_FUNDS_CHECKER_PKG
  PSA_FUNDS_CHECKER_PKG
  GL_FUNDS_AVAILABLE_PKG
–获取程序包版本
select us.text || ' – ' || uo.status
  from user_source us, user_objects uo
 where us.name IN ('GL_FUNDS_AVAILABLE_PKG')
   and uo.object_name IN ('GL_FUNDS_AVAILABLE_PKG')
   and us.line = 2
   and us.name = uo.object_name
   and us.type = uo.object_type
   and (us.text like '%glifundb.pls%');

–主要记录最近一次预算资金检查时的统计信息
select * from psa_bc_xml_clob;