利用DBMS_ADVISOR.TUNE_MVIEW包生成物化视图创建语句

不少人大概和我一样在创建物化视图的时候会犯头痛,怎样合理的改写SQL语句以及添加物化视图日志需要经过慎重精密的考虑。有了DBMS_ADVISOR.TUNE_MVIEW存储过程这个帮手后,极大地方便了DBA或应用设计人员创建和优化物化视图。该TUNE_MVIEW存储过程可以做到优化物化视图中的查询定义,修正物化视图日志的问题,此外它还能为原先不能refresh fast的物化视图提出建议以使得其可以快速刷新。


SQL> CREATE MATERIALIZED VIEW MACLEAN.STRMTS 
  2  USING INDEX REFRESH FAST ON DEMAND 
  3  ENABLE QUERY REWRITE 
  4  AS select distinct t1,t2 from MACLEAN.strb;
AS select distinct t1,t2 from MACLEAN.strb
                                      *
ERROR at line 4:
ORA-12015: cannot create a fast refresh materialized view from a complex query


/* 以select distinct查询语句为例,该语句本身不符合refresh fast的标准,但TUNE_MVIEW存储过程
    可以将这种查询变形使得满足快速刷新的条件 */

--    PROCEDURE DBMS_ADVISOR.TUNE_MVIEW
--    PURPOSE: Tune a Create Materialized View statement to
--    ADVISOR SUPPORT:        SQL Access Advisor
--    PARAMETERS:
--         TASK_NAME
--            The user can pass in a user-defined task name or
--            get a returned system-generated task name.
--         MV_CREATE_STMT
--            CREATE MATERIALIZED VIEW SQL statement to tune

procedure tune_mview (task_name      in out varchar2,
                      mv_create_stmt in     clob);

SQL> set serveroutput on;

SQL> declare
  2    tn varchar2(200);
  3  begin
  4    DBMS_ADVISOR.TUNE_MVIEW(tn,
  5                            mv_create_stmt => 'CREATE MATERIALIZED VIEW MACLEAN.STRMTS 
  6                     USING INDEX REFRESH FAST ON DEMAND 
  7                     ENABLE QUERY REWRITE 
  8                     AS select distinct t1,t2 from MACLEAN.strb');
  9    dbms_output.put_line(tn);
 10  end;
 11  /
TASK_484

PL/SQL procedure successfully completed.

SQL> select script_type,statement
  2    from dba_tune_mview
  3   where task_name = 'TASK_484'
  4   order by action_id;
 
SCRIPT_TYPE    STATEMENT

IMPLEMENTATION CREATE MATERIALIZED VIEW LOG ON "MACLEAN"."STRB" WITH ROWID, SEQUENCE ("T1","T2")  INCLUDING NEW VALUES
IMPLEMENTATION ALTER MATERIALIZED VIEW LOG FORCE ON "MACLEAN"."STRB" ADD ROWID, SEQUENCE ("T1","T2")  INCLUDING NEW VALUES
IMPLEMENTATION CREATE MATERIALIZED VIEW MACLEAN.STRMTS USING INDEX  REFRESH FAST WITH ROWID ENABLE QUERY REWRITE AS SELECT MACLEAN.STRB.T2 C1, MACLEAN.STRB.T1 C2, COUNT(*) M1 FROM MACLEAN.STRB GROUP BY MACLEAN.STRB.T2, MACLEAN.STRB.T1
UNDO           DROP MATERIALIZED VIEW MACLEAN.STRMTS

/* 可以看到TUNE_MVIEW存储过程将原查询变形为SELECT...GROUP BY的形式 */

SQL> CREATE MATERIALIZED VIEW LOG ON "MACLEAN"."STRB" WITH ROWID, SEQUENCE ("T1","T2")  INCLUDING NEW VALUES;
Materialized view log created.

SQL> ALTER MATERIALIZED VIEW LOG FORCE ON "MACLEAN"."STRB" ADD ROWID, SEQUENCE ("T1","T2")  INCLUDING NEW VALUES;
Materialized view log altered.

SQL> CREATE MATERIALIZED VIEW MACLEAN.STRMTS USING INDEX  REFRESH FAST WITH ROWID 
ENABLE QUERY REWRITE AS SELECT MACLEAN.STRB.T2 C1, MACLEAN.STRB.T1 C2, COUNT(*) M1 
FROM MACLEAN.STRB GROUP BY MACLEAN.STRB.T2, MACLEAN.STRB.T1;

Materialized view created.

针对那些确实无法快速刷新的复杂查询,TUNE_MVIEW过程也可能给出将一个查询分解为多个物化视图达到快速刷新和查询重写的目的:



SQL> CREATE MATERIALIZED VIEW MACLEAN.STRMTD 
  2  USING INDEX REFRESH FAST
  3  ON DEMAND ENABLE QUERY REWRITE AS 
  4  select t2,t3,count(*) from strc group by t2,t3 
  5  union all
  6  select t2,t3,count(*) from strd group by t2,t3;
select t2,t3,count(*) from strd group by t2,t3
                           *
ERROR at line 6:
ORA-12015: cannot create a fast refresh materialized view from a complex query


SQL> set serveroutput on;
SQL> declare
  2    tn varchar2(200);
  3  begin
  4    DBMS_ADVISOR.TUNE_MVIEW(tn,
  5                            mv_create_stmt => 'CREATE MATERIALIZED VIEW MACLEAN.STRMTC
  6                                                   USING INDEX REFRESH FAST
  7                                                   ON DEMAND ENABLE QUERY REWRITE AS
  8                                                   select t2,t3,count(*) from strc group by t2,t3
  9                                                   union all
 10                                                  select t2,t3,count(*) from strd group by t2,t3');
 11    dbms_output.put_line(tn);
 12  end;
 13  /
TASK_547

PL/SQL procedure successfully completed.

SQL> select statement
  2    from dba_tune_mview
  3   where task_name = 'TASK_547'
  4   order by action_id;

CREATE MATERIALIZED VIEW LOG ON "MACLEAN"."STRC" WITH ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES
ALTER MATERIALIZED VIEW LOG FORCE ON "MACLEAN"."STRC" ADD ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES
CREATE MATERIALIZED VIEW LOG ON "MACLEAN"."STRD" WITH ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES
ALTER MATERIALIZED VIEW LOG FORCE ON "MACLEAN"."STRD" ADD ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES
CREATE MATERIALIZED VIEW MACLEAN.STRMTC$SUB1 USING INDEX  REFRESH FAST WITH ROWID ON COMMIT ENABLE QUERY REWRITE AS SELECT MACLEAN.STRC.T3 C1, MACLEAN.STRC.T2 C2, COUNT(*) M1 FROM MACLEAN.STRC GROUP BY MACLEAN.STRC.T3, MACLEAN.STRC.T2
DROP MATERIALIZED VIEW MACLEAN.STRMTC$SUB1
CREATE MATERIALIZED VIEW MACLEAN.STRMTC$SUB2 USING INDEX  REFRESH FAST WITH ROWID ON COMMIT ENABLE QUERY REWRITE AS SELECT MACLEAN.STRD.T3 C1, MACLEAN.STRD.T2 C2, COUNT(*) M1 FROM MACLEAN.STRD GROUP BY MACLEAN.STRD.T3, MACLEAN.STRD.T2
DROP MATERIALIZED VIEW MACLEAN.STRMTC$SUB2
CREATE MATERIALIZED VIEW MACLEAN.STRMTC USING INDEX  REFRESH FORCE WITH ROWID ENABLE QUERY REWRITE AS  (SELECT "STRMTC$SUB1"."C2" "T2","STRMTC$SUB1"."C1" "T3","STRMTC$SUB1"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB1" "STRMTC$SUB1") UNION ALL  (SELECT "STRMTC$SUB2"."C2" "T2","STRMTC$SUB2"."C1" "T3","STRMTC$SUB2"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB2" "STRMTC$SUB2")
DROP MATERIALIZED VIEW MACLEAN.STRMTC
DBMS_ADVANCED_REWRITE.BUILD_SAFE_REWRITE_EQUIVALENCE ('MACLEAN.STRMTC$RWEQ','select t2,t3,count(*) from strc group by t2,t3
                                                 union all
                                                select t2,t3,count(*) from strd group by t2,t3',' (SELECT "STRMTC$SUB1"."C2" "T2","STRMTC$SUB1"."C1" "T3","STRMTC$SUB1"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB1" "STRMTC$SUB1") UNION ALL  (SELECT "STRMTC$SUB2"."C2" "T2","STRMTC$SUB2"."C1" "T3","STRMTC$SUB2"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB2" "STRMTC$SUB2")',600916906)
 
DBMS_ADVANCED_REWRITE.DROP_REWRITE_EQUIVALENCE('MACLEAN.STRMTC$RWEQ')

SQL> CREATE MATERIALIZED VIEW LOG ON "MACLEAN"."STRC" WITH ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES;

Materialized view log created.

SQL> ALTER MATERIALIZED VIEW LOG FORCE ON "MACLEAN"."STRC" ADD ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES;

Materialized view log altered.

SQL> CREATE MATERIALIZED VIEW LOG ON "MACLEAN"."STRD" WITH ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES;

Materialized view log created.

SQL> ALTER MATERIALIZED VIEW LOG FORCE ON "MACLEAN"."STRD" ADD ROWID, SEQUENCE ("T2","T3")  INCLUDING NEW VALUES;

Materialized view log altered.

SQL> CREATE MATERIALIZED VIEW MACLEAN.STRMTC$SUB1 USING INDEX  REFRESH FAST WITH ROWID 
ON COMMIT ENABLE QUERY REWRITE AS SELECT MACLEAN.STRC.T3 C1, MACLEAN.STRC.T2 C2, COUNT(*) M1 
FROM MACLEAN.STRC GROUP BY MACLEAN.STRC.T3, MACLEAN.STRC.T2;

Materialized view created.

SQL> CREATE MATERIALIZED VIEW MACLEAN.STRMTC$SUB2 USING INDEX  REFRESH FAST WITH ROWID 
ON COMMIT ENABLE QUERY REWRITE AS SELECT MACLEAN.STRD.T3 C1, MACLEAN.STRD.T2 C2, COUNT(*) M1 
FROM MACLEAN.STRD GROUP BY MACLEAN.STRD.T3, MACLEAN.STRD.T2;

Materialized view created.

SQL> CREATE MATERIALIZED VIEW MACLEAN.STRMTC USING INDEX  REFRESH FORCE WITH ROWID 
ENABLE QUERY REWRITE AS  
(SELECT "STRMTC$SUB1"."C2" "T2","STRMTC$SUB1"."C1" "T3","STRMTC$SUB1"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB1" "STRMTC$SUB1") 
UNION ALL  
(SELECT "STRMTC$SUB2"."C2" "T2","STRMTC$SUB2"."C1" "T3","STRMTC$SUB2"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB2" "STRMTC$SUB2");

Materialized view created.

declare
  v_state varchar2(2000);
begin
  select statement
    into v_state
    from dba_tune_mview
   where task_name = 'TASK_547'
     and action_id = 15;
  v_state := 'begin ' || v_state || '; end;';
  dbms_output.put_line(v_state);
  execute immediate v_state;
end;
PL/SQL procedure successfully completed.

SQL> set linesize 200 pagesize 1400;
SQL> select t2,t3,count(*) from strc group by t2,t3 
  2  union all
  3  select t2,t3,count(*) from strd group by t2,t3;
no rows selected

---------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |     2 |    74 |     4  (50)| 00:00:01 |
|   1 |  UNION-ALL                    |             |       |       |            |          |
|   2 |   MAT_VIEW REWRITE ACCESS FULL| STRMTC$SUB1 |     1 |    37 |     2   (0)| 00:00:01 |
|   3 |   MAT_VIEW REWRITE ACCESS FULL| STRMTC$SUB2 |     1 |    37 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

/* 可以看到查询成功被rewrite为对2个物化视图的扫描 */

Oracle中可被并行化执行的SQL操作

并不是所有的SQL operations都是可并行化的;不少人认为sort merge join这种排序合并操作是不能并行化的,这显示是一种错误的认识。有了这样一个列表你就可以更好地理解Oracle中的Parallel Execution了:

Parallel Query:
Table scan
Nested loop join
Sort merge join
NOT IN
GROUP BY
Hash join
SELECT DISTINCT
UNION and UNION ALL
Aggregation
PL/SQL functions called from SQL
ORDER BY

DDL:
CREATE TABLE AS SELECT
CREATE INDEX
Rebuild index
Move partition
Split partition

DML:
UPDATE   on partitioned table
DELETE   on partitioned table
MERGE    on partitioned table
INSERT … SELECT
Enable constraint (the table scan is parallelized)
Star transformation

Oracle Advanced Security:Column Encryption Overhead

在Oracle 10g中出现了column encryption列加密特性,通过对列上的数据加密实现数据安全性的目的。当然实现这一加密特性是有代价的,一方面会导致所加密列数据每行所占磁盘空间字节数增长,另一方面会消耗更多的cpu和内存资源。

当使用Oracle的TDE(transparent data encryption)加密数据表的某一列时将导致该表上每行数据所占用的空间大致增加33-51个字节,这几十个字节用作以下用途:

  • 其中20个字节用以对加密值的完整性检查,该部分可以通过’nomac’选项来省略
  • 同时加密会填补加密值到16个字节(如果列本身长度不够的话),举例来说如果是9个字节长度的number类型,那么加密该number字段时就会需要将该数据填补到16个字节,也就是额外地多用了7个字节
  • 加密时默认采用salt选项(default),salt是指一串长度为16个字节的随机string,在数据被正式加密前这串string将会被添加到列上,这种做法使得黑客无法通过比对已知的密文来匹配加密值(steal patterns of ciphertext to known ciphertext);salt总是位于加密数据的末尾;该部分可以通过no salt选项来省略。

注意默认使用salt选项加密的列是不能创建索引的,所以强烈建议加密列时强制使用no salt选项!加密列上的索引不支持范围扫描操作(Range scans on encrypted columns can’t use index),而加密表空间(encryption tablespace)没该限制。

SQL> create table enctab (t1 int encrypt);
Table created.

SQL>  create index ind_enc on enctab(t1);
create index ind_enc on enctab(t1)
*
ERROR at line 1:
ORA-28338: Column(s) cannot be both indexed and encrypted with salt

SQL> create table news (t1 varchar2(1) encrypt);
Table created.

/*以默认的salt和mac选项创建示例用表 */

SQL> insert into news values('1');
1 row created.

SQL> commit;
Commit complete.

/* 该列本身的长度为1个字节 */

SQL> select dump(t1,16) from news;

DUMP(T1,16)
--------------------------------------------------------------------------------
Typ=1 Len=1: 31

/* 以下为该行的dump信息,可以看到加密值增长到了52字节 */
col  0: [52]
de 76 08 74 2a c0 e3 94 89 e6 a8 3b 22 54 ca e5 af 4d eb a0 26 a7 e5 c2 f5
c0 e5 3a a0 09 9a 08 fa 56 2a 92 a0 83 b3 7f 0b 99 03 ad 12 78 d4 03 ec 6e
b3 c2

针对加密列可以使用’nomac’和no salt选项来减少性能损耗,其中’no mac’选项用以允许Oracle省略在加密数据中产生和存放message authentication code(MAC,信息验证代码),如上文所述的这部分代码用以对加密值的完整性检查,会占用20个字节的空间。通过使用’nomac’选项可以有效较少加密和后续操作所额外消耗的cpu周期,同时为加密值的存储减少20个字节的开销。
另外no salt选项用以省略加密中加入的16个字节的随机字符串(string),在能保证列值都唯一的情况下(攻击者无法通过已知密文比对的方式来解密),使用该选项可以有效减少cpu周期和每个单元16字节的空间开销。

askmac.cn>create table Maclean (t1 varchar2(16) encrypt no salt 'nomac');

/* 注意这里的nomac要被单引号括起来 */

askmac.cn>alter table table_name modify column_name encrypt [using ] [no salt] ['nomac'];

此外目前列加密不支持外键约束,造成这种限制的原因是每张表都有其唯一的密钥(encryption key);而表空间加密则不存在这种限制,即便某个从属表不在加密表空间上。

SQL> create table man (t1 int primary key );
Table created.

SQL> create table woman(t1 int encrypt);
Table created.

SQL>  alter table woman add constraint fk foreign key(t1) references man(t1);
 alter table woman add constraint fk foreign key(t1) references man(t1)
                                                 *
ERROR at line 1:
ORA-28335: referenced or referencing FK constraint column cannot be encrypted

列加密特性对于表连接(table joining)来说是透明的,即便作为连接条件的列被加密了也是如此(join tables is transparent,even if the columns for join condition are encrypted)。同时分区键是不能作为加密列的,否则将出现ORA-28346: an encrypted column cannot serve as a partitioning column错误。
此外加密列索引存在诸多限制,总结加密列索引(Indexes On Encrypted Columns)的几个restrictions:

  1. 只有使用no salt选项加密的列上才允许创建索引
  2. 加密列上不支持位图索引
  3. 加密列不支持外键
  4. 加密列上创建的索引只能做等式查询,因为不能做Range scan所以如between,like等非等式查询是不支持的;这种限制是由于索引中的数据也被加密了,所以实际上数据是以加密后的形式来排序的。所有非等式查询的条件均无法利用到索引,而使用全表扫描。
  5. 如果应用不使用等式查询的话,那么建议不要在加密列上创建索引,因为这样无益与性能,反而会增加性能开销。

而加密表空间(TDE Tablespace Encryption)不存在以上关于索引的限制,甚至在加密表空间上的表的索引在非加密表空间上也不会影响其使用,包括Range Scans;显然这一点出乎许多人的意料:

SQL> select tablespace_name,ENCRYPTED from dba_tablespaces  where tablespace_name in ('ENC','USERS');
TABLESPACE_NAME                ENC
------------------------------ ---
ENC                            YES
USERS                          NO

SQL> create table tv tablespace enc as select * from dba_objects;
Table created.

SQL> create index pk_tv on tv(object_id) tablespace enc;
Index created.

SQL> set autotrace on;
SQL> select 1 from tv where object_id=9999;
         1
----------
         1

Execution Plan
----------------------------------------------------------
Plan hash value: 2009574168
--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| PK_TV |     1 |    13 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("OBJECT_ID"=9999)

/* 将该索引移动至非加密表空间上 */

SQL> alter index pk_tv rebuild tablespace users;
Index altered.

SQL> select 1 from tv where object_id=9999;

         1
----------
         1

Execution Plan
----------------------------------------------------------
Plan hash value: 2009574168
--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| PK_TV |     1 |    13 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("OBJECT_ID"=9999)

/* 可以看到虽然索引被移动到非加密表空间上但仍可以被利用到并range scan */

SQL> create bitmap index obj_typ on tv (object_type) tablespace users;
Index created.

/* 创建位图索引也没有问题 */

当然表空间加密也仍然存在一些限制:

  • 加密表空间不能使用传统的exp/imp工具导入导出,而只能使用datapump工具
  • 显然External Large Objects (BFILEs)这种存储在数据库外的外部大对象也不受支持。

Oracle数据库升级前必要的准备工作

Oracle数据库升级向来是一门纷繁复杂的工程,DBA需要为产品数据库的升级耗费大量时间精力在准备工作上;因为其升级复杂度高,所以即便做了较为充分的准备仍可能在升级过程中遇到意想不到的问题,为了更高效地完成升级任务和减少停机时间,我们有必要为升级工作营造一种”舒适的”防御式的数据库”氛围”:

1.为了保障升级后的数据库性能,我们有必要在升级前有效地收集数据库的性能统计信息,以便升级后若发生性能问题可以做出对比:

  • 为了保证性能统计信息真实有效,有必要在数据库升级前的一个月即开展收集工作
  • 收集的性能统计信息应当尽可能的精确真实
  • 在Oracle 8i/9i中使用Statspack性能报表,将快照级别设置为6或更高,设置快照间隔为30分钟,在具体升级前将perfstat用户使用exp工具导出,参考Metalink文档Note:466350.1介绍了若何对比升级前后的Statspack快照
  • 在Oracle 10g/11g中使用AWR自动负载仓库性能报告,保证采集30天左右的快照,快照间隔最好为30-60分钟;之后可以使用dbms_swrf_internal.awr_extract存储过程将AWR导出到dumpfile文件,在升级完成后载入这部分AWR信息,并可以使用DBMS_WORKLOAD_REPOSITORY.AWR_DIFF_REPORT_HTML函数对比升级前后的性能

2.正式升级前的防御性措施:

  • 过多的审计信息可能会导致升级速度下降,可以在升级前将审计数据导出,并清理审计字典基表:
截断SYS.AUD$基表:
SQL>TRUNCATE TABLE SYS.AUD$;
  • 同样的有必要清理10g后出现的回收站:
清理DBA回收站:
SQL>purge DBA_RECYCLEBIN;
  • 移除一些”过期”的参数,设置这些参数的原因很有可能是为了修正原版本上的一些问题,例如我们都会做的设置event参数;但在新版本中这些参数是否仍有必要设置是一个值得讨论的问题,当然你完全可以就此事去提交一个SR:
这些"过期"参数可能包括:过老的如optimizer_features_enable=8.1.7.4,_always_semi_join=off,_unnest_subquery=false
或者event = "10061 trace name context forever, level 10",如此之类等等。
  • 为数据库中的数据字典收集统计信息:
在Oracle 9i中可以执行以下过程收集数据字典统计信息,
SQL> exec DBMS_STATS.GATHER_SCHEMA_STATS
     ('SYS', options => 'GATHER',estimate_percent =>
      DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR
      ALL COLUMNS SIZE AUTO', cascade => TRUE);

在Oracle10g/11g中收集字典统计信息可以由GATHER_DICTIONARY_STATS存储过程来完成:
SQL> exec DBMS_STATS.GATHER_DICTIONARY_STATS;
  • 为策万全,我们有必要为回退数据库升级任务做好准备,10g以前只能通过备份恢复来完成,10g以后我们可以利用闪回数据库的还原点特性来回退数据库,但需要注意以下几点:
    • 利用还原点要求数据库处于归档且打开flashback database的模式下
    • 在特性仅在版本10.2之后可用
    • 必须保证闪回回复区flashback recovery area有足够的磁盘空间
    • 注意在升级后不要立即修改compatible参数,restore point无法跨越compatible工作
/* 首先我们在正式升级前创建一个有效的保证闪回数据库的还原点 */

SQL> create restore point pre11gupgrd guarantee flashback database;
Restore point created.

/* 确认以上4个注意后,我们可以大胆放心地实施升级工作了 */
SQL> shutdown immediate;
..............
SQL> @?/rdbms/admin/catupgrd.sql
.............
upgrade failed

/* 在升级过程中出现了不可绕过的错误时,我们可能不得不回退数据库到还原点,也就是升级前*/

/* 关闭实例后,还原环境到10g下 */

SQL> startup mount;

/* 正式闪回到还原点pre11gupgrd */
SQL> flashback database to restore point pre11gupgrd;
Flashback complete.

SQL> alter database open;
alter database open
*
ERROR at line 1:
ORA-01589: must use RESETLOGS or NORESETLOGS option for database open

SQL>  alter database open resetlogs;

/* 以resetlogs打开数据库 */

/* 之后有必要删除这一个还原点 */
SQL> select * from v$restore_point;

       SCN DATABASE_INCARNATION# GUA STORAGE_SIZE
---------- --------------------- --- ------------
TIME
---------------------------------------------------------------------------
NAME
--------------------------------------------------------------------------------
   5081633                     3 YES     15941632
08-FEB-11 08.20.33.000000000 PM
PRE11GUPGRD

SQL> drop restore point pre11gupgrd;
Restore point dropped.
  • 下载最新版本的预升级检查脚本(pre-upgrade check script),如utlu102i.sql / utlu111i.sql / utlu112i.sql;Metalink文档Note:884522.1 <How to Download and Run Oracle’s Database Pre-Upgrade Utility> 指出了各版本utluxxx脚本的下载地址
/* 将升级信息spool到日志文件中 */
SQL> SPOOL /tmp/UPGRADE/utlu112i.log
SQL> @/tmp/UPGRADE/utlu112i.sql
  • 需要关注SYS和SYSTEM用户模式下的失效对象,有必要在升级前修复所有的失效对象:
SELECT UNIQUE object_name, object_type, owner
  FROM dba_objects
 WHERE status = 'INVALID';
  • 在升级完成后推荐执行utlrp.sql脚本以重新编译(Recompile)对象,从11.1.0.7开始升级前后的失效对象将自动对比,执行?/rdbms/admin/utluiobj.sql脚本可以列出对比信息,同时基表registry$sys_inv_objs和registry$nonsys_inv_objs分别列出了数据库中失效的sys或非sys对象:
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

SQL> @?/rdbms/admin/utluiobj.sql
.
Oracle Database 11.1 Post-Upgrade Invalid Objects Tool 02-08-2011 22:23:22
.
This tool lists post-upgrade invalid objects that were not invalid
prior to upgrade (it ignores pre-existing pre-upgrade invalid objects).
.
Owner                     Object Name                     Object Type
.
SH            FWEEK_PSCAT_SALES_MV               MATERIALIZED VIEW

PL/SQL procedure successfully completed.

3.解决升级过程中失效的组件(component)

  • 确保该部分组件确实被link到目前的Oracle软件2进制可执行文件或库文件中
  • 如果确认不会用到某些组件(component),想要通过手动彻底移除这部分组件(亦或者希望reinstall重新安装这部分组件),那么可以参考以下文档:
Note:472937.1 Information On Installed Database Components/Schemas
Note.300056.1 Debug and Validate Invalid Objects
Note:753041.1 How to diagnose Components with NON VALID status
Note.733667.1 How to Determine if XDB is Being Used in the Database?

组件升级失败实例1:数据库从10.2升级到11.2,在10g的环境中Database Vault组件已经安装,
Database Vault组件在升级relink前被turned off,在升级到11.2的过程中XDB组件升级失败;
其原因在于安装或切换Database Vault将使得XDB组件失效,或者由Bug 8942758引起。
解决方案是在升级前执行utlrp.sql脚本重新编译失效对象和组件,在此例中执行utlrp.sql可以使XDB组件valid.

组件升级失败实例2:数据库从10.2.0.4升级到11.1.0.7,在升级过程中"ORACLE SERVER"组件失效;
其原因在于DMBS_SQLPA包引用了某个不存在的列,该问题可以参考metalink文档782735.1和Notes:605317.1/736353.1。
有效的解决方案是:
1.在升级前将SYS.PLAN_TABLE$基表或者同义词PUBLIC.PLAN_TABLE DROP掉
2.若已执行了升级操作并遭遇了该问题,那么可以使用以下手段修复该问题:
@catplan.sql -- recreate the plan table
@dbmsxpln.sql -- reload dbms_xplan spec
@prvtxpln.plb -- reload dbms_xplan implementation
@prvtspao.plb -- reload dbms_sqlpa
alter package SYS.DBMS_SUMADVISOR compile ;
alter package SYS.DBMS_SUMADVISOR compile body;

4. 使用例如AIX上的slibclean等命令清理操作系统环境,在少数专有平台上不清理载入的共享库文件可能导致升级失败

5.在执行catupgrd.sql脚本正式升级前打开sqlplus的echo输出,将升级过程中所有的输出信息转储到日志文件中:

SQL> set echo on

SQL> SPOOL /tmp/upgrade.log

SQL> @catupgrd.sql
SQL> spool off

DBUA图形化升级工具默认使用spool和”echo”输出,这些日志可以在$ORACLE_HOME/cfgtoollogs/dbua//upgrade/目录下找到。

Who pulls the background process dbwr’s trigger?

到底是谁扣动了database writer的扳机?初学Oracle的朋友都会对dbwr这个后台进程有一种模糊的印象,dbwr何时会被触发?很多人大约会回答当发生检查点或者当某些脏块在LRU链表上处于较冷的一端时。同时又有许多关注于宏观架构的工程师会将dbwr的写出规律归结为是lazy(懒)的。Oracle作为目前市场占有率最高的商用数据库,其各种内部算法都可以算得上是商业机密;虽然不断有专家为我们”解密”,但在我的观念中这些内部原理都与真理之冠有着不大不小的差别。所以显然我要描述的是我个人对于database writer以及cache management(缓存管理)的理解,这些理解在一定程度上是能够自洽的,但我无法保证它们必然准确无误。

要详细描述dbwr的工作原理,我们需要从久远年代的版本V7323说起,当时的db writer和cache management已经十分成熟了,8i以后只是引入了增量检查点等特性,dba不用再关心db writer受一些细节参数的影响,而只需要关注增量检查点的活跃程度就可以了。以下我们列出在V7323中,dbwr可能被触发写出的几种情况:

a.当前台进程需要将磁盘上的物理数据块读取到数据库高速缓存中(db cache)时,其首先需要在数据库缓存中寻找到一块可用的free(空闲) buffer。为了寻找这样free buffer,该前台进程首先需要以排他方式持有相关LRU链表的latch(闩),并在该LRU链表上扫描所可用的Free buffer,扫描都会从LRU链表的尾端开始,也就是”较冷”的一端。在此过程中,前台进程沿着由尾到头的方向所遍历到的脏块将被移动到LRUW链表上(注意:一个buffer同时只可能处于一个链表上);此外相关的统计信息如dirty buffer inspectedfree buffers inspected将会累增。若该前台进程在LRU链表上搜索的范围超过了整个LRU链表长度*(隐式参数_db_block_max_scan_count/100)所规定的阀值时,其搜索操作将自行中止,该前台进程还会以信号通知dbwr进程并释放其所持有的LRU latch。dbwr后台进程在收到前台进程的信号信息后,会执行一次大批量的写出操作以使得LRU链表上有干净的clean buffer可用,在此过程中前台进程将处于free buffer wait等待事件中。dbwr后台进程为了写出LRUW与(LRU链表尾部)的脏块,其会主动去持有LRU latch并扫描该LRU链表(也是从尾部开始)试图找出脏块,并批量写出这些收集到得脏块。该DBWR的扫描深度(DBWR scan depth)由隐式参数_db_writer_scan_depth_pct的所指定,当DBWR所扫描的LRU链表长度等于整个LRU链表长度*(_db_writer_scan_depth_pct/100)时,DBWR将停止继续扫描LRU链表。

8i以后:以上这种情况一言以蔽之就是DBWR write for Free Request,这种情况在8i以后仍然奏效;hidden parameter _db_block_max_scan_pct依然健在,其默认值为40,当然也可以从x$kvit视图中”Max percentage of LRU list foreground can scan for free”相关列观察到。到10.1版本中_db_writer_scan_depth_pct(Percentage of LRU buffers for dbwr to scan when looking for dirty)仍健在其默认值为25,在10.2中被彻底废弃。由于引入了增量检查点,DBWn也会主动去遍历LRU链表,将发现的Dirty Buffer移至Checkpoint Queue(dirty queue)上,该扫描同样也受到隐式参数_db_writer_scan_depth_pct的限制。

b.若前台进程在遍历LRU链表,顺带将脏块(dirty block)移动到LRUW链表上时,前台进程可能意识到LRUW链表的长度已经达到了某种阀值。该阀值定义了dirty queue(脏队列)的最大长度,该阀值一般受隐式参数2*_db_block_write_batch或_db_large_dirty_queue的影响。当此时刻LRUW链表将不在接受任何脏块(dirty buffer)。DBWR后台进程将被通知完成批量清理脏块的任务。在此情形下,DBWR处于一种”慌乱”状态中将不遗余力地去清理LRUW与LRU(仍需扫描,扫描深度如上述参数)链表中的脏块。与此同时,前台进程将被禁止访问LRU链表以避免产生进一步弄脏块和扫描操作。这种情形很像操作系统空闲内存小于所设minfree时,所发生的paging。此外在V7323中DBWR进程批量写出IO的大小受制于隐式参数_db_block_write_batch的值,因为该参数在之后的版本中被彻底废弃了,所以不再介绍。

8i以后:此情形仍将触发DBWR写出,但_db_block_write_batch隐式参数被彻底废弃,所以实际限制dirty queue(checkpoint queue)长度的是隐式参数_db_large_dirty_queue,其默认为25个buffer;该参数也可以通过x$kvit内部视图的”kcbldq large dirty queue if kcbclw reaches this”观察,该参数到11.2中依然健在。

c.DBWR后台进程每三秒空闲超时后被唤醒,每次超时均会唤醒DBWR去遍历buffer headers(扫描2*_db_block_write_batch个块)以寻找并写出任意脏块(排序块,临时块会被跳过)。这样做的目的是不让DBWR过于空闲。

8i以后:DBWR仍会通过调用semtimedop函数陷入3s一次的睡眠中,若在过去三秒中DBWR始终空闲,那么在它醒来后会写出少量的脏块到磁盘上。但不同于早期版本,目前版本中DBWR会每三秒根据增量检查点的要求写出脏块(脏块来源于CKPT-Q链表及由DBWR进程主动去扫描LRU链表的tail)。详见Jonathan Lewis的<How have the log_checkpoint_interval and log_checkpoint_timeout changed from version 7?>:

“(Oracle decided to keep trickling dirty blocks to disc at a higher rate than had been effected by the old 3-second idle write rate (every 3 seconds, dbwr wakes up and writes a few blocks to disc if it has had no other work in the interval).? To achieve this, they changed the meaning of the two log checkpoint parameters. This change was made possible by a change in the architecture of the buffer management, which now allows Oracle to queue dirty buffers in the order that they were first made dirty ??.Amongst other things, Oracle already kept a low redo block address (lrba)on each buffer header for each dirty buffer. This identifies the first redo block that started the process of changing that buffered block from the state that is currently on disc to the dirty state that is in the buffer. The function of the log_checkpoint_interval is simply to limit the distance between a buffer’s lrba and the addreess of the redo block that lgwr is currently writing. If the lrba is too low, then the block was first dirtied too long ago and it has to be written to disc (and its lrba set to zero). Since Oracle now queues dirty blocks in the order they were first dirtied (i.e. lrba order) it is a quick and cheap process to find such blocks.For example: if lgwr is currently writing redo block 12,100 and the log_checkpoint_interval is set to 4,000, then dbwr will be cued to write any dirty blocks with an lrba less than 8,100. This check is carried out every 3 seconds, and I believe the control files and possibly any affected data files are updated with the SCN at which this incremental checkpoint took place.)” http://www.jlcomp.demon.co.uk/faq/log_checkpoint.html

d.8i以前不存在incremental checkpoint增量检查点,完全检查点发生时,LGWR将通知DBWR写出一系列的current,dirty和非临时buffer到磁盘上。注意因检查点写出的buffer块并不会被置为free状态,这些脏块仍保留在数据库高速缓存中,以减少不必要的物理IO。因为8i以后的检查点已发生巨大转变,故不再展开。

8i以后:完全检查点为增量检查点所”取代”,完全检查点仅在alter system checkpoint或shutdown(非abort)等少数情况下发生,增量检查点会引发checkpoint queue(dirty queue)上的脏块递进地被写出,每三秒CKPT后台进程将计算检查点目标RBA(Redo Block Address),该目标RBA基于:当前RBA,log_checkpoint_timeout,log_checkpoint_interval,fast_start_mttr_target,fast_start_io_target,最小在线日志的大小等因素。当增量检查点发生时所有在目标RBA相应时间之前被弄脏的buffer块都当被写出(When a checkpoint is initiated, DBWR writes all buffers on the queue until the checkpoint RBA is less than the head of the CKPTQ RBA)。在Oracle 10g中实现了自动调整检查点,只要不显示地(explicitly)设置参数FAST_START_MTTR_TARGET为零,自动检查点调整都将被启用,数据库将以较低的I/O负载写出脏块以提高性能。需要注意的是当启用mttr advisor时有必要将log_checkpoint_timeout,log_checkpoint_interval,fast_start_io_target三个参数设置为零。– DBWR write For checkpoint。


e.9i以前的rac称作”ops oracle parallel server”,因为当时还没有出现cache fusion功能,所以节点间同步缓存需要通过将current块写入到磁盘上来完成,这种因为block ping request的需求而导致的DBWR写出,可以归类为write for ping request (The biggest performance robber in the OPS architecture was the DB block ping. A DB block ping would occur when an instance participating in an OPS database had a block in its cache that another participating instance required. In OPS, if another instance required the block in the cache of a second instance, the block would have to be written out to disk, the locks transferred, and then the block re-read into the requesting instance.)

8i以后:在Oracle 8i的ops中初步实现了cache fusion(Oracle 8i (OPS) introduced the initial phase of cache fusion. The data blocks were transferred from the SGA of one instance to the SGA of another instance without the need to write the blocks to disk.)到9i中cache fusion技术日渐成熟,ops也更名为”RAC real application cluster”以区别于老式的cluster。因为cache fusion这一革命性的特性出现,9i以后的oracle cluster中dbwr被从需要不断完成write for ping request的性能窘境中拯救出来了;因而block ping request这种触发写出的条件也不再成立。

ORA-19808错误一例

一套Linux上的11.2.0.2 RAC系统,其中一个节点startup mount时出现ORA-19808错误,日志如下:


SQL> alter database mount;
alter database mount
*
ERROR at line 1:
ORA-01105: mount is incompatible with mounts by other instances
ORA-19808: recovery destination parameter mismatch


SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, Real Application Clusters, OLAP, Data Mining
and Real Application Testing options


[oracle@rh3 ~]$ oerr ora 19808
19808, 00000, "recovery destination parameter mismatch"
// *Cause:  The value of parameters DB_RECOVERY_FILE_DEST and
//          DB_RECOVERY_FILE_DEST_SIZE must be same in all instances.
//          instance. All databases must have same recovery destination
//          parameters.
// *Action: Check DB_RECOVERY_FILE_DEST and DB_RECOVERY_FILE_DEST_SIZE
//          values in all instances.

SQL> col name for a30
SQL> col value for a30

SQL> select name ,value,inst_id from gv$system_parameter  where name='db_recovery_file_dest_size';

NAME                           VALUE                             INST_ID
------------------------------ ------------------------------ ----------
db_recovery_file_dest_size     0                                       1
db_recovery_file_dest_size     42278584320                             2

该错误是由于启动节点使用了pfile形式的参数文件,而该参数文件中的db_recovery_file_dest_size值与已经启动的另一个节点的db_recovery_file_dest_size不一致所造成。

如果使用共享的server parameter file则不可能出现上述情况,当然也可以通过在启动节点上修改db_recovery_file_dest_size来解决问题。

January 2011 Patch set Update发布

January 2011补丁集更新在大约2周前发布了,与Oracle Database相关的psu分别为10.2.0.5.2,10.2.0.4.7(REQUIRES PRE-REQUISITE 10.2.0.4.4),11.2.0.1.4,11.2.0.2.1.

安装oracle 10.2.0.4 on aix 6.1的不同之处

 

 

根据Oracle Database Installation Guide 10g Release 2 (10.2) for AIX 5L Based Systems (64-Bit)文档,在AIX 6.1上安装ORACLE 10g Release 2时,须额外注意以下事项,以下内容来自文档Minimum Software Versions and Patches Required to Support Oracle Products on IBM Power Systems [ID 282036.1]中的”IBM Software Requirements and PTFs for AIX 6.1 support of Oracle Database 10g Release 2 (10.2.0.1 or higher)”部分的内容:
1.操作系统版本在AIX 6.1 SP 1 (AIX 6100-00-01)及以上时, 确认打上以下APAR补丁:
IZ10223: OLSON TIMEZONE SETTINGS IS NOT WORKING FOR 64BIT APPLICATIONS. APPLIES TO AIX 6100-00
2.编译程序Compilers
在AIX 6.1和Oracle 10gR2,下面的编译程序被认证:
Micro Focus Server Express 4.0 SP1
ACUCOBOL-GT 6.1
OC Systems PowerAda 5.3+
编译程序的认证情况参考:
MetaLink Note 43208.1, Certified Compilers, for the latest patch information and references to compiler-specific MetaLink notes.
3.当运行Oracle 10gR2的”rootpre.sh”时,可能显示不正常的AIX AIO的错误信息:
“Configuring Asynchronous I/O….
Asynchronous I/O is not installed on this system.
You will need to install it, and either configure it yourself using
‘smit aio’ or rerun the Oracle root installation procedure.
Configuring POSIX Asynchronous I/O….
Posix Asynchronous I/O is not installed on this system.
You will need to install it, and either configure it yourself using
‘smit aio’ or rerun the Oracle root installation procedure.”
解决:
下载并使用rootpre.sh的替换版本:10.2.0.3版本上的patch 6718715。
4.当安装oracle 10gR2, 11gR1 or 11gR2在AIX 6.1服务器上时,可能出现以下错误: “Id: 0706-010 The binder was killed by a signal: Segmentation fault”。
以下特定的AIX 6.1 TL版本与SP版本有此类问题, 须确认使用相应版本的APAR补丁。详细信息参考 Metalink note 1264074.1.
? AIX 6.1 TL2 SP10 and higher
? AIX 6.1 TL3 SP7 and higher, IZ89304
? AIX 6.1 TL4 SP7 and higher, IZ89302
? AIX 6.1 TL5 SP3 and higher, IZ89300
? AIX 6.1 TL6 (all SP levels), IZ88711  <<—
? AIX 6.1 TL7 (all SP levels)
5.安装时使用”./runInstaller -ignoreSysPrereqs”
6.确认已安装包bos.adt.libm, bos.adt.prof, bos.cifs_fs.rte
lslpp -l bos.adt.base bos.adt.lib bos.adt.libm bos.perf.perfstat bos.perf.libperfstat bos.perf.proctools bos.adt.prof bos.cifs_fs.rte
7.HACMP and PowerHA认证情况
For AIX 6.1 and Oracle RAC 10gR2, HACMP 5.4.1 and PowerHA 5.5 and 6.1 are certified.
其他操作系统问题,如AIO、paging等异常系统性能异常等问题,请参考文档:Minimum Software Versions and Patches Required to Support Oracle Products on IBM Power Systems [ID 282036.1]中的”Additional AIX 6.1 Information”部分。
8.补丁选择
10.2.0.4的PSU补丁有(标有overlay的PSU表示需要在PSU 10.2.0.4.4的基础上安装):
12827778    10.2.0.4.10 Patch Set Update (PSU) Overlay
12419397    10.2.0.4.9 Patch Set Update (PSU) Overlay
11724977    10.2.0.4.8 Patch Set Update (PSU) Overlay
10248636    10.2.0.4.7 Patch Set Update (PSU) Overlay
9952234    10.2.0.4.6 Patch Set Update (PSU) Overlay
9654991    10.2.0.4.5 Patch Set Update (PSU) Overlay
9352164    10.2.0.4.4 Patch Set Update (PSU)
9119284    10.2.0.4.3 Patch Set Update (PSU)
8833280    10.2.0.4.2 Patch Set Update (PSU)
8576156    10.2.0.4.1 Patch Set Update (PSU)
在ORACLE 10.2.0.4版本上,ORACLE推荐使用PSU 10.2.0.4.4 + PSU 10.2.0.4.10(overlay) + Patch 10139235 + Patch 12582245
具体请查看:PSU 10.2.0.4 Patch Set – Availability and Known Issues [ID 555579.1]

PL/SQL Product Sample Code

PL/SQL Product Sample Code

create or replace package XXPAY_ETN_PAY_DIFF_REPORT_PKG is
  -- $ETNHeader: $
  --------------------------------------------------------------------------------------------------
  --    Owner        : EATON CORPORATION.
  --    Application  : Human Resources
  --    Schema       : APPS
  --    Compile AS   : APPS
  --    File Name    : XXPAY_ETN_PAY_DIFF_REPORT_PKG.PKS
  --    Date         : 28-Jun-2014
  --    Author       : TCS
  --    Description  : Package for custom program for XXPAY Payroll Difference Report
  --
  --    Version      : $ETNHeader: $
  --
  --    Parameters  : ERRBUF   -StANDar concurrent prog parameters   
  --                  RETCODE  -StANDar concurrent prog parameters 
  --                  p_payroll_id - Payroll for report.
  --                  p_payroll_period_id  - pay period for report.
  --                   p_organization_id - organization id for report.
  --                  p_element_bal  - elements and balance for report
  --                  p_threshold  - threshold for report
  --                  p_percent - percent for report               
  --
  --    Change History
  --  ========================================================================================
  --         Ver 1.0           Pushkar      28-Jun-2014     Creation
  --  ========================================================================================
  -- =============================================================================================
  -- Procedure: XXPAY_PAY_DIFF_REPORT
  -- =============================================================================================
  --   This procedure generates the XML for the Payroll Difference Report
  -- =============================================================================================                                 

  PROCEDURE XXPAY_PAY_DIFF_REPORT(errbuf              OUT VARCHAR2,
                                  retcode             OUT VARCHAR2,
                                  p_payroll_id        IN NUMBER,
                                  p_payroll_period_id IN NUMBER,
                                  p_organization_id   IN NUMBER,
                                  p_element_bal       IN VARCHAR2,
                                  p_threshold         IN VARCHAR2,
                                  p_percent           IN VARCHAR2);

END;
/
CREATE OR REPLACE PACKAGE BODY XXPAY_ETN_PAY_DIFF_REPORT_PKG IS
  -- $ETNHeader: $
  --------------------------------------------------------------------------------------------------
  --    Owner        : EATON CORPORATION.
  --    Application  : Human Resources
  --    Schema       : APPS
  --    Compile AS   : APPS
  --    File Name    : XXPAY_ETN_PAY_DIFF_REPORT_PKG.PKB
  --    Date         : 28-Jun-2014
  --    Author       : TCS
  --    Description  : Package for custom program for XXPAY Payroll Difference Report
  --
  --    Version      : $ETNHeader: $
  --
  --    Parameters  : ERRBUF   -StANDar concurrent prog parameters   
  --                  RETCODE  -StANDar concurrent prog parameters 
  --                  p_payroll_id - Payroll for report.
  --                  p_payroll_period_id  - pay period for report.
  --                  p_organization_id - organization id for report.
  --                  p_element_bal  - elements and balance for report
  --                  p_threshold  - threshold for report
  --                  p_percent - percent for report               
  --
  --    Change History
  --  ========================================================================================
  --         Ver 1.0           Pushkar      28-Jun-2014     Creation
  --         Ver 2.0           Pushkar      13-Aug-2014     Change for termination date
  --                                                         and '&' character to'&'   
  --  ========================================================================================

  PROCEDURE XXPAY_PAY_DIFF_REPORT(errbuf              OUT VARCHAR2,
                                  retcode             OUT VARCHAR2,
                                  p_payroll_id        IN NUMBER,
                                  p_payroll_period_id IN NUMBER,
                                  p_organization_id   IN NUMBER,
                                  p_element_bal       IN VARCHAR2,
                                  p_threshold         IN VARCHAR2,
                                  p_percent           IN VARCHAR2) IS
  
    CURSOR EMP_PAY_DIFF_CUR(v_payroll_id         IN NUMBER,
                            v_prev_pay_period_id IN NUMBER,
                            v_organization_id    IN NUMBER) IS
      SELECT *
        FROM (SELECT papf1.employee_number Employee_Number,
                     papf1.Full_name Full_Name,
                     papf1.PER_INFORMATION14 Employee_Name,
                     REPLACE(apps.XXPAY_ETN_RPT_UTIL.get_activity_center(paa.assignment_id,
                                                                         ptp.end_date),
                             '&',
                             '&') Activity_centre,
                     REPLACE((SELECT name
                               FROM apps.hr_all_organization_units haou
                              WHERE haou.organization_id =
                                    paaf.organization_id),
                             '&',
                             '&') Organization,
                     papf1.national_identifier National_Identifier,
                     REPLACE(PG.name, '&', '&') GRADE_NAME,
                     REPLACE((SELECT location_code
                               FROM apps.hr_locations_all
                              WHERE location_id = paaf.location_id),
                             '&',
                             '&') Location,
                     to_char(ppos.date_start, 'DD-MON-YYYY') NEW_HIRE_DATE,
                     to_char(ppos.actual_termination_date, 'DD-MON-YYYY') TERMINATION_DATE,
                     ppa.payroll_action_id,
                     ptp.period_name,
                     papf.payroll_name,
                     ptp.time_period_id,
                     paa.assignment_action_id,
                     papf1.business_group_id,
                     ptp.end_date,
                     paaf.assignment_id,
                     ptp.payroll_id,
                     to_char(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                 paaf.business_group_id,
                                                                 'Total Payments',
                                                                 '_ASG_PTD',
                                                                 PAYROLL_PERIOD_DATES.CURR_PAY_DATE)) TOT_PAY_BAL_CURRENT,
                     to_char(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                 paaf.business_group_id,
                                                                 'Total Payments',
                                                                 '_ASG_PTD',
                                                                 PAYROLL_PERIOD_DATES.PREV_PAY_DATE)) TOT_PAY_BAL_PREVIOUS,
                     
                     (to_number(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                    paaf.business_group_id,
                                                                    'Total Payments',
                                                                    '_ASG_PTD',
                                                                    PAYROLL_PERIOD_DATES.CURR_PAY_DATE)) -
                     to_number(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                    paaf.business_group_id,
                                                                    'Total Payments',
                                                                    '_ASG_PTD',
                                                                    PAYROLL_PERIOD_DATES.PREV_PAY_DATE))) GAP,
                     ABS(round(((to_number(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                               paaf.business_group_id,
                                                                               'Total Payments',
                                                                               '_ASG_PTD',
                                                                               PAYROLL_PERIOD_DATES.CURR_PAY_DATE)) -
                               to_number(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                               paaf.business_group_id,
                                                                               'Total Payments',
                                                                               '_ASG_PTD',
                                                                               PAYROLL_PERIOD_DATES.PREV_PAY_DATE))) /
                               decode(to_number(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                                     paaf.business_group_id,
                                                                                     'Total Payments',
                                                                                     '_ASG_PTD',
                                                                                     PAYROLL_PERIOD_DATES.CURR_PAY_DATE)),
                                       0,
                                       1,
                                       to_number(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(paaf.assignment_id,
                                                                                     paaf.business_group_id,
                                                                                     'Total Payments',
                                                                                     '_ASG_PTD',
                                                                                     PAYROLL_PERIOD_DATES.CURR_PAY_DATE)))),
                               2)) GAP_PERCENT,
                     payroll_period_dates.curr_period_name CURRENT_PAYROLL,
                     payroll_period_dates.prev_period_name PREVIOUS_PAYROLL,
                     payroll_period_dates.curr_time_period_id CURRENT_PAYPERIOD_ID,
                     payroll_period_dates.CURR_PAY_DATE CURRENT_PAYPERIOD_END_DATE,
                     payroll_period_dates.prev_time_period_id PREVIOUS_PAYPERIOD_ID,
                     payroll_period_dates.PREV_PAY_DATE PREVIOUS_PAYPERIOD_END_DATE
                FROM apps.pay_all_payrolls_f papf,
                     apps.pay_payroll_actions ppa,
                     apps.pay_assignment_actions paa,
                     apps.per_time_periods ptp,
                     apps.per_people_f papf1,
                     apps.per_assignments_f paaf,
                     apps.per_periods_of_service ppos,
                     apps.per_grades pg,
                     (SELECT ptp2.end_date       PREV_PAY_DATE,
                             ptp1.end_date       CURR_PAY_DATE,
                             ptp2.period_name    PREV_PERIOD_NAME,
                             PTP1.PERIOD_NAME    curr_period_name,
                             ptp2.time_period_id PREV_TIME_PERIOD_ID,
                             ptp1.time_period_id CURR_TIME_PERIOD_ID,
                             ptp1.payroll_id
                        FROM per_time_periods ptp1, per_time_periods ptp2
                       WHERE ptp1.time_period_id = P_Payroll_period_id
                         AND ptp2.time_period_id = V_PREV_PAY_PERIOD_ID
                         AND ptp2.payroll_id = ptp1.payroll_id) PAYROLL_PERIOD_DATES
               WHERE papf.payroll_id = (v_payroll_id)
                 AND payroll_period_dates.payroll_id = ptp.payroll_id
                 AND ptp.time_period_id IN
                     ((p_payroll_period_id), v_prev_pay_period_id)
                 AND paaf.assignment_id = paa.assignment_id
                 AND papf.payroll_id = ppa.payroll_id
                 AND paa.payroll_action_id = ppa.payroll_action_id
                 AND ppa.time_period_id = ptp.time_period_id
                 AND paaf.period_of_service_id = ppos.period_of_service_id
                 AND paa.assignment_id <> -1
                 AND paaf.assignment_type = 'E'
                 AND ppa.effective_date BETWEEN ptp.start_date AND
                     ptp.end_date
                 AND EXISTS
               (SELECT 'X'
                        FROM per_all_assignments_f  paaf1,
                             pay_assignment_actions paa2,
                             pay_payroll_actions    PPA2,
                             Per_time_periods       ptp2
                       WHERE paaf1.person_id = paaf.person_id
                         AND paaf1.assignment_id = paa2.assignment_id
                         AND ppa2.payroll_action_id = paa2.payroll_action_id
                         AND ppa2.time_period_id = ptp2.time_period_id
                         AND ppa2.action_status = 'C'
                         AND ppa2.action_type IN ('R', 'Q', 'B', 'V', 'I')
                         AND ptp2.time_period_id IN
                             ((P_Payroll_period_id), v_prev_pay_period_id)
                       HAVING COUNT(DISTINCT(ptp2.period_name)) = 2)
                 AND paaf.grade_id = pg.grade_id(+)
                 AND papf1.person_id = paaf.person_id
                 AND trunc(ptp.end_date) between papf1.effective_start_date AND
                     papf1.effective_end_date
                 AND trunc(ptp.end_date) BETWEEN papf.effective_start_date AND
                     papf.effective_end_date
                 AND ppos.person_id = paaf.person_id
                 AND trunc(nvl(ppos.actual_termination_date, ptp.end_date)) between
                     paaf.effective_start_date AND paaf.effective_end_date
                 AND (Paaf.organization_id IN (v_organization_id) OR
                     LEAST(v_organization_id) IS NULL)
                 AND primary_flag = 'Y'
                 AND ppa.action_status = 'C'
                 AND ppa.action_type IN ('R', 'Q', 'B', 'V', 'I'))
       order by ACTIVITY_CENTRE, EMPLOYEE_NUMBER, TIME_PERIOD_ID;
  
    CURSOR Elements_balance_VALUE_CUR(V_Payroll_NAME      IN VARCHAR,
                                      V_time_period_id    IN NUMBER,
                                      V_assignment_id     IN NUMBER,
                                      V_business_group_id IN NUMBER,
                                      V_END_DATE          IN DATE) IS
      SELECT substr(flv.meaning, 0, instr(flv.meaning, '|') - 1) UNIT_NAME,
             substr(flv.meaning,
                    instr(flv.meaning, '|') + 1,
                    length(flv.meaning)) UNIT_VALUE_NAME,
             flv.description ELEMENT_UNIT,
             APPS.XXPAY_ETN_RPT_UTIL.GET_RUN_RESULT(substr(flv.meaning,
                                                           0,
                                                           instr(flv.meaning,
                                                                 '|') - 1),
                                                    substr(flv.meaning,
                                                           instr(flv.meaning,
                                                                 '|') + 1,
                                                           length(flv.meaning)),
                                                    V_Payroll_NAME,
                                                    V_time_period_id,
                                                    V_assignment_id) UNIT_RESULT,
             flv.lookup_code ELE_BAL_CODE
        FROM apps.fnd_lookup_values flv
       WHERE flv.lookup_type = 'XXPAY_CN_ELEMENTS_BALANCE'
         AND flv.attribute1 = 'E'
         AND flv.enabled_flag = 'Y'
         AND language = 'US'
         AND (flv.meaning IN (P_element_bal) or
             LEAST(P_element_bal) IS NULL)
         AND flv.tag = 'CN'
      UNION
      SELECT substr(flv.meaning, 0, instr(flv.meaning, '|') - 1) UNIT_NAME,
             substr(flv.meaning,
                    instr(flv.meaning, '|') + 1,
                    length(flv.meaning)) UNIT_VALUE_NAME,
             flv.description ELEMENT_UNIT,
             to_char(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(V_assignment_id,
                                                         V_business_group_id,
                                                         substr(flv.meaning,
                                                                0,
                                                                instr(flv.meaning,
                                                                      '|') - 1),
                                                         substr(flv.meaning,
                                                                instr(flv.meaning,
                                                                      '|') + 1,
                                                                length(flv.meaning)),
                                                         V_END_DATE)) UNIT_RESULT,
             flv.lookup_code ELE_BAL_CODE
        FROM apps.fnd_lookup_values flv
       WHERE flv.lookup_type = 'XXPAY_CN_ELEMENTS_BALANCE'
         AND flv.attribute1 = 'B'
         AND flv.enabled_flag = 'Y'
         AND language = 'US'
         AND (flv.meaning IN (P_element_bal) or
             LEAST(P_element_bal) IS NULL)
         AND flv.tag = 'CN'
      UNION
      SELECT 'TOTAL_PAYMENT' UNIT_NAME,
             'ASG_RUN' UNIT_VALUE_NAME,
             'Total Payment' ELEMENT_UNIT,
             to_char(APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(V_assignment_id,
                                                         V_business_group_id,
                                                         'Total Payments',
                                                         '_ASG_PTD',
                                                         V_END_DATE)) UNIT_RESULT,
             
             '00001' ELE_BAL_CODE
        FROM DUAL
      UNION
      SELECT 'Percentage' UNIT_NAME,
             'Percentage' UNIT_VALUE_NAME,
             'Percentage' ELEMENT_UNIT,
             NULL UNIT_RESULT,
             '000015' ELE_BAL_CODE
        FROM DUAL
       ORDER BY ELE_BAL_CODE;
  
    CURSOR Elements_balance_VALUE_DIFF(V_Payroll_NAME        IN VARCHAR,
                                       V_CURR_time_period_id IN NUMBER,
                                       V_PREV_time_period_id IN NUMBER,
                                       V_assignment_id       IN NUMBER,
                                       V_business_group_id   IN NUMBER,
                                       V_CURR_END_DATE       IN DATE,
                                       V_PREV_END_DATE       IN DATE,
                                       V_PERCENTAGE          IN NUMBER) IS
      SELECT substr(flv.meaning, 0, instr(flv.meaning, '|') - 1) UNIT_NAME,
             substr(flv.meaning,
                    instr(flv.meaning, '|') + 1,
                    length(flv.meaning)) UNIT_VALUE_NAME,
             flv.description ELEMENT_UNIT,
             TO_CHAR(TO_NUMBER(APPS.XXPAY_ETN_RPT_UTIL.GET_RUN_RESULT(substr(flv.meaning,
                                                                             0,
                                                                             instr(flv.meaning,
                                                                                   '|') - 1),
                                                                      substr(flv.meaning,
                                                                             instr(flv.meaning,
                                                                                   '|') + 1,
                                                                             length(flv.meaning)),
                                                                      V_Payroll_NAME,
                                                                      V_CURR_time_period_id,
                                                                      V_assignment_id)) -
                     TO_NUMBER(APPS.XXPAY_ETN_RPT_UTIL.GET_RUN_RESULT(substr(flv.meaning,
                                                                             0,
                                                                             instr(flv.meaning,
                                                                                   '|') - 1),
                                                                      substr(flv.meaning,
                                                                             instr(flv.meaning,
                                                                                   '|') + 1,
                                                                             length(flv.meaning)),
                                                                      V_Payroll_NAME,
                                                                      V_PREV_time_period_id,
                                                                      V_assignment_id))) UNIT_RESULT,
             flv.lookup_code ELE_BAL_CODE
        FROM apps.fnd_lookup_values flv
       WHERE flv.lookup_type = 'XXPAY_CN_ELEMENTS_BALANCE'
         AND flv.attribute1 = 'E'
         AND flv.enabled_flag = 'Y'
         AND language = 'US'
         AND (flv.meaning IN (P_element_bal) or
             LEAST(P_element_bal) IS NULL)
         AND flv.tag = 'CN'
      UNION
      SELECT substr(flv.meaning, 0, instr(flv.meaning, '|') - 1) UNIT_NAME,
             
             substr(flv.meaning,
                    instr(flv.meaning, '|') + 1,
                    length(flv.meaning)) UNIT_VALUE_NAME,
             flv.description ELEMENT_UNIT,
             to_char((APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(V_assignment_id,
                                                          V_business_group_id,
                                                          substr(flv.meaning,
                                                                 0,
                                                                 instr(flv.meaning,
                                                                       '|') - 1),
                                                          substr(flv.meaning,
                                                                 instr(flv.meaning,
                                                                       '|') + 1,
                                                                 length(flv.meaning)),
                                                          V_CURR_END_DATE)) -
                     (APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(V_assignment_id,
                                                          V_business_group_id,
                                                          substr(flv.meaning,
                                                                 0,
                                                                 instr(flv.meaning,
                                                                       '|') - 1),
                                                          substr(flv.meaning,
                                                                 instr(flv.meaning,
                                                                       '|') + 1,
                                                                 length(flv.meaning)),
                                                          V_PREV_END_DATE))) UNIT_RESULT,
             flv.lookup_code ELE_BAL_CODE
        FROM apps.fnd_lookup_values flv
       WHERE flv.lookup_type = 'XXPAY_CN_ELEMENTS_BALANCE'
         AND flv.attribute1 = 'B'
         AND flv.enabled_flag = 'Y'
         AND language = 'US'
         AND (flv.meaning IN (P_element_bal) or
             LEAST(P_element_bal) IS NULL)
         AND flv.tag = 'CN'
      UNION
      SELECT 'TOTAL_PAYMENT' UNIT_NAME,
             'ASG_RUN' UNIT_VALUE_NAME,
             'Total Payment' ELEMENT_UNIT,
             to_char((APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(V_assignment_id,
                                                          V_business_group_id,
                                                          'Total Payments',
                                                          '_ASG_PTD',
                                                          V_CURR_END_DATE)) -
                     (APPS.XXPAY_ETN_RPT_UTIL.GET_BALANCE(V_assignment_id,
                                                          V_business_group_id,
                                                          'Total Payments',
                                                          '_ASG_PTD',
                                                          V_PREV_END_DATE))) UNIT_RESULT,
             '00001' ELE_BAL_CODE
        FROM DUAL
      UNION
      SELECT 'Percentage' UNIT_NAME,
             'Percentage' UNIT_VALUE_NAME,
             'Percentage' ELEMENT_UNIT,
             TO_CHAR(V_PERCENTAGE) UNIT_RESULT,
             '000015' ELE_BAL_CODE
        FROM DUAL
       ORDER BY ELE_BAL_CODE;
  
    V_PREV_PAY_PERIOD_ID NUMBER;
    V_payroll_name       VARCHAR2(100);
    V_TIME_PERIOD        VARCHAR2(100);
    V_organization_name  VARCHAR2(100);
    V_period_name        VARCHAR2(100);
    e_error_EXCEPTION EXCEPTION;
    v_error_msg VARCHAR2(1000);
  
  BEGIN
  
    BEGIN
    
      SELECT Payroll_name
        INTO V_payroll_name
        FROM pay_all_payrolls_f
       WHERE payroll_id = P_Payroll_id;
    
      SELECT ptp2.time_period_id
        INTO V_PREV_PAY_PERIOD_ID
        FROM per_time_periods ptp1, per_time_periods ptp2
       WHERE ptp2.end_date = ptp1.start_date - 1
         AND ptp2.payroll_id = ptp1.payroll_id
         AND ptp1.time_period_id = P_Payroll_period_id;
    
      SELECT Period_name
        INTO V_period_name
        FROM per_time_periods
       WHERE time_period_id = P_Payroll_period_id;
    
    EXCEPTION
      WHEN OTHERS THEN
        v_error_msg := 'Error In fetching parameters' || '-' || SQLERRM;
        RAISE e_error_EXCEPTION;
      
    END;
  
    BEGIN
    
      SELECT name
        INTO V_organization_name
        FROM hr_all_organization_units
       WHERE organization_id = P_organization_id;
    
    EXCEPTION
      WHEN OTHERS THEN
        V_organization_name := NULL;
      
    End;
  
    fnd_file.put_line(fnd_file.output, '');
    fnd_file.put_line(fnd_file.output, '');
    fnd_file.put_line(fnd_file.output,
                      '' || P_Payroll_id || '');
    fnd_file.put_line(fnd_file.output,
                      '' || P_Payroll_period_id ||
                      '');
    fnd_file.put_line(fnd_file.output,
                      '' || V_organization_name ||
                      '');
    fnd_file.put_line(fnd_file.output,
                      '' || 'NULL' ||
                      '');
    fnd_file.put_line(fnd_file.output,
                      '' || P_THRESHOLD || '');
    fnd_file.put_line(fnd_file.output,
                      '' || P_PERCENT || '');
  
    For I_EMPLOYEE_REC IN EMP_PAY_DIFF_CUR(P_Payroll_id,
                                           V_PREV_PAY_PERIOD_ID,
                                           P_organization_id) loop
    
      IF (I_EMPLOYEE_REC.GAP >= P_threshold or
         I_EMPLOYEE_REC.GAP_PERCENT >= P_PERCENT) THEN
      
        IF I_EMPLOYEE_REC.TIME_PERIOD_ID =
           I_EMPLOYEE_REC.Current_Payperiod_Id THEN
          V_TIME_PERIOD := '2.CURRENT';
        ELSIF I_EMPLOYEE_REC.TIME_PERIOD_ID =
              I_EMPLOYEE_REC.Previous_payperiod_id THEN
          V_time_period := '1.PREVIOUS';
        END IF;
      
        FOR I_ELE_BAL_REC IN Elements_balance_VALUE_CUR(I_EMPLOYEE_REC.payroll_name,
                                                        I_EMPLOYEE_REC.TIME_PERIOD_ID,
                                                        I_EMPLOYEE_REC.Assignment_Id,
                                                        I_EMPLOYEE_REC.Business_Group_Id,
                                                        I_EMPLOYEE_REC.END_DATE) loop
        
          fnd_file.put_line(fnd_file.output, '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.Employee_Number ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.Employee_name ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.activity_centre ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.ORGANIZATION ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.national_identifier ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.grade_name ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.location ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.NEW_HIRE_DATE ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.TERMINATION_DATE ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.Payroll_action_id ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.Payroll_Name ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.Period_name ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.time_period_id ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.Assignment_action_id ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.business_group_id ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.END_DATE ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.ASSIGNMENT_ID ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_ELE_BAL_REC.UNIT_Name ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_ELE_BAL_REC.UNIT_Value_name ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_ELE_BAL_REC.ELEMENT_UNIT ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_ELE_BAL_REC.UNIT_RESULT ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_ELE_BAL_REC.ELE_BAL_CODE ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' || V_TIME_PERIOD || '-' ||
                            I_EMPLOYEE_REC.PERIOD_NAME || '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.payroll_id ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.Tot_Pay_Bal_Current ||
                            '');
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.Tot_Pay_Bal_Previous ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.GAP || '');
          fnd_file.put_line(fnd_file.output,
                            '' || I_employee_rec.GAP_PERCENT ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.CURRENT_PAYROLL ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.CURRENT_PAYPERIOD_ID ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.CURRENT_PAYPERIOD_END_DATE ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.PREVIOUS_PAYROLL ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.PREVIOUS_PAYPERIOD_ID ||
                            '');
        
          fnd_file.put_line(fnd_file.output,
                            '' ||
                            I_employee_rec.PREVIOUS_PAYPERIOD_END_DATE ||
                            '');
        
          fnd_file.put_line(fnd_file.output, '');
        
        END LOOP;
      
        IF I_EMPLOYEE_REC.TIME_PERIOD_ID =
           I_EMPLOYEE_REC.Current_Payperiod_Id THEN
        
          BEGIN
          
            FOR I_EMP_DIFF IN Elements_balance_VALUE_DIFF(I_EMPLOYEE_REC.payroll_name,
                                                          I_EMPLOYEE_REC.TIME_PERIOD_ID,
                                                          I_EMPLOYEE_REC.PREVIOUS_PAYPERIOD_ID,
                                                          I_EMPLOYEE_REC.Assignment_Id,
                                                          I_EMPLOYEE_REC.Business_Group_Id,
                                                          I_EMPLOYEE_REC.END_DATE,
                                                          I_EMPLOYEE_REC.PREVIOUS_PAYPERIOD_END_DATE,
                                                          I_EMPLOYEE_REC.GAP_PERCENT) LOOP
            
              fnd_file.put_line(fnd_file.output, '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Employee_Number ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Employee_name ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.activity_centre ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.ORGANIZATION ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.national_identifier ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_employee_rec.grade_name ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_employee_rec.location ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.NEW_HIRE_DATE ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.TERMINATION_DATE ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Payroll_action_id ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Payroll_Name ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Period_name ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.time_period_id ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Assignment_action_id ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.business_group_id ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_employee_rec.END_DATE ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.ASSIGNMENT_ID ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_EMP_DIFF.UNIT_Name ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_EMP_DIFF.UNIT_Value_Name ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_EMP_DIFF.ELEMENT_UNIT ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_EMP_DIFF.UNIT_RESULT ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_EMP_DIFF.ELE_BAL_CODE ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || '3.GAP-GAP' ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' || I_employee_rec.payroll_id ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Tot_Pay_Bal_Current ||
                                '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.Tot_Pay_Bal_Previous ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' || I_employee_rec.GAP || '');
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.GAP_PERCENT ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.CURRENT_PAYROLL ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.CURRENT_PAYPERIOD_ID ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.CURRENT_PAYPERIOD_END_DATE ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.PREVIOUS_PAYROLL ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.PREVIOUS_PAYPERIOD_ID ||
                                '');
            
              fnd_file.put_line(fnd_file.output,
                                '' ||
                                I_employee_rec.PREVIOUS_PAYPERIOD_END_DATE ||
                                '');
            
              fnd_file.put_line(fnd_file.output, '');
            
            END LOOP;
          
          END;
        
        END IF;
      
      END IF;
    
    END LOOP;
  
    fnd_file.put_line(fnd_file.output, '');
    fnd_file.put_line(fnd_file.output,
                      '' || V_payroll_name ||
                      '');
    fnd_file.put_line(fnd_file.output, '');
    fnd_file.put_line(fnd_file.output, '');
    fnd_file.put_line(fnd_file.output,
                      '' || V_period_name ||
                      '');
    fnd_file.put_line(fnd_file.output, '');
    fnd_file.put_line(fnd_file.output, '');
  
  EXCEPTION
    WHEN e_error_exception THEN
    
      fnd_file.put_line(fnd_file.log, V_error_msg);
      ERRBUF  := V_error_msg;
      RETCODE := 2;
    
    WHEN OTHERS THEN
    
      fnd_file.put_line(fnd_file.log, SQLERRM);
      ERRBUF  := SQLERRM;
      RETCODE := 2;
    
  END;

END;
/



解决Oracle错误ORA-15061一例

一套Linux上的11.2.0.1系统,告警日志中出现以下错误:

ORA-00202: control file: '+DATA/controlfile/current.256.7446483424'
ORA-17505: ksfdrsz:1 Failed to resize file to size 612 blocks
ORA-15061: ASM operation not supported [41]
WARNING: Oracle Managed File +FRA in the recovery area is orphaned by the control file.
The control file can not keep all recovery area files due to space limitation.
krse.c
Archived Log entry 200 added for thread 1 sequence 200 ID 0x3739c2f0 dest 1:

RMAN backup failed with

Rman backup error:
RMAN-03009: failure of backup command on ORA_DISK_1 channel at 
ORA-19510: failed to set size of 6800 blocks for file "+FRA" (block size=8192)
ORA-17505: ksfdrsz:1 Failed to resize file to size 6800 blocks
ORA-15061: ASM operation not supported [41]

[oracle@rh2 ~]$ oerr ora 15061
15061, 00000, "ASM operation not supported [%s]"
// *Cause:  An ASM operation was attempted that is invalid or not supported
//          by this version of the ASM instance.
// *Action: This is an internal error code that is used for maintaining
//          compatibility between software versions and should never be
//          visible to the user; contact Oracle support Services.
//

提交SR后,根据Oracle GCS确认为BUG:9788316:

1.The following error indicates that it failed to resize the controlfile to 612 blocks. If the DB_BLOCK_SIZE is 8192, 
then 612 blocks is not more than 5MB. According to the results of the query on V$ASM_DISKGROUP in 'results01.txt' file, 
the ASM diskgroup +DATA has 108605 MB free space. So, the ASM diskgroup +DATA has enough space for the 612 blocks.

2. By the way, please confirm whether you have recently applied PSU #1. Anyway, 
please try to relink the Oracle executables, as shown here. Before you run the "relink" command, 
make sure to shutdown both the ASM instance and target database.

$ORACLE_HOME/bin/relink all

3 After relinking the Oracle executables, please confirm whether you are still 
experiencing the same ORA-15061 error.

ORA-15061: ASM Operation Not Supported [41] After Apply PSU #1 (Doc ID 1126113.1)
ORA-15061 reported while doing a file operation with 11.1 or 11.2 ASM after PSU applied in database home (Doc ID 1070880.1)

Hdr: 9788316 11.2.0.1.1 RDBMS 11.2.0.1.0 ASM PRODID-5 PORTID-267
Abstract: AFTER APPLY PSU 1 (11.2.0.1.1) ON RDBMS HOME UNABLE TO RESIZE ASM DATAFILE.

*** 06/07/10 02:09 pm ***
—-
3-1827355081

PROBLEM:
——–
1) After apply PSU 1 (11.1.0.2.1) on the 11.2.0.1.0 RDBMS Oracle Home
customer is unable to resize an ASM datafile:
============================================================
SQL> alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560M;
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560M
*
ERROR at line 1:
ORA-1237: cannot extend datafile 4
ORA-1110: data file 4: ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
ORA-17505: ksfdrsz:1 Failed to resize file to size 71680 blocks
ORA-15061: ASM operation not supported [41]

============================================================

2) DB alertlog reports (alert_brg13ed1.log):
============================================================

Mon Jun 07 11:27:57 2010
Stopping background process CJQ0
Mon Jun 07 12:30:28 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 536870915
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 536870915…
Mon Jun 07 13:07:40 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560m
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560m…
Mon Jun 07 13:49:50 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 800M
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 800M…
Mon Jun 07 13:58:51 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560M
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560M…
Mon Jun 07 14:25:43 2010

============================================================

3) ASM alert.log does not report any problem.

DIAGNOSTIC ANALYSIS:
——————–
(see below)

WORKAROUND:
———–
None

RELATED BUGS:
————-

REPRODUCIBILITY:
—————-

TEST CASE:
———-

STACK TRACE:
————

SUPPORTING INFORMATION:
———————–

24 HOUR CONTACT INFORMATION FOR P1 BUGS:
—————————————-

DIAL-IN INFORMATION:
——————–

IMPACT DATE:
————

*** 06/07/10 02:09 pm ***
4) I can confirm that at (Jun 07 10:55:59 EDT 2010) customer installed the
Patch: 9355126 (on the Grid OH), which includes the fix for Bug: 8898852:
============================================================

Invoking OPatch 11.2.0.1.2

Oracle Interim Patch Installer version 11.2.0.1.2

Oracle Home : /u01/grid/oracle/product/grid
Central Inventory : /u01/app/oracle/oraInventory
from : /var/opt/oracle/oraInst.loc
OPatch version : 11.2.0.1.2
OUI version : 11.2.0.1.0
OUI location : /u01/grid/oracle/product/grid/oui
——————————————————————————

Installed Top-level Products (1):

Oracle Grid Infrastructure
11.2.0.1.0
There are 1 products installed in this Oracle Home.

Installed Products (87):

There are 87 products installed in this Oracle Home.

Interim patches (1) :

Patch 9355126 : applied on Mon Jun 07 10:55:59 EDT 2010
Unique Patch ID: 12175902
Created on 5 Feb 2010, 07:38:30 hrs PST8PDT
Bugs fixed:
8974548, 8898852
============================================================

5) Also, I can confirm that at (Mon May 03 00:01:14 EDT 2010) customer
installed the 11.2.0.1.1 Patch Set Update (PSU #1) which include as well the
patch for Bug: 8898852 (on the RDBMS OH):
============================================================
Invoking OPatch 11.2.0.1.2

Oracle Interim Patch Installer version 11.2.0.1.2

Oracle Home : /u01/app/oracle/product/11.2.0/db1
Central Inventory : /u01/app/oracle/oraInventory
from : /var/opt/oracle/oraInst.loc
OPatch version : 11.2.0.1.2
OUI version : 11.2.0.1.0
OUI location : /u01/app/oracle/product/11.2.0/db1//oui

——————————————————————————

Installed Top-level Products (1):

Oracle Database 11g
11.2.0.1.0
There are 1 products installed in this Oracle Home.

Installed Products (134):

. 11.2.0.1.0
There are 134 products installed in this Oracle Home.

Interim patches (1) :

Patch 9352237 : applied on Mon May 03 00:01:14 EDT 2010
Unique Patch ID: 12366369
Created on 6 Apr 2010, 05:03:41 hrs PST8PDT
Bugs fixed:
8661168, 8769239, 8898852, 8801119, 9054253, 8706590, 8725286, 8974548
8778277, 8780372, 8769569, 9027691, 9454036, 9454037, 9454038, 8761974
7705591, 8496830, 8702892, 8639114, 8723477, 8729793, 8919682, 8818983
9001453, 8475069, 9328668, 8891929, 8798317, 8820324, 8733749, 8702535
8565708, 9036013, 8735201, 8684517, 8870559, 8773383, 8933870, 8812705
8405205, 8822365, 8813366, 8761260, 8790767, 8795418, 8913269, 8897784
8760714, 8717461, 8671349, 8775569, 8898589, 8861700, 8607693, 8642202
8780281, 9369797, 8780711, 8784929, 8834636, 9015983, 8891037, 8828328
8570322, 8832205, 8665189, 8717031, 8685253, 8718952, 8799099, 8633358
9032717, 9321701, 8588519, 8783738, 8796511, 8782971, 8756598, 9454385
8856497, 8703064, 9066116, 9007102, 8721315, 8818175, 8674263, 9352237
8753903, 8720447, 9057443, 8790561, 8733225, 9197917, 8928276, 8991997,
8837736
============================================================

6) But the problem persists:
============================================================
SQL> alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560M;
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560M
*
ERROR at line 1:
ORA-1237: cannot extend datafile 4
ORA-1110: data file 4: ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
ORA-17505: ksfdrsz:1 Failed to resize file to size 71680 blocks
ORA-15061: ASM operation not supported [41]

============================================================

7) 11.2.0.1.1 Patch Set Update (PSU #1) should include the fix for bug:
8898852 (ORA-15061: ASM operation not supported [41]).
This PSU contains a fix that adds an operation to the ASM protocol.
The problem is that the PSU has been applied correctly to the RDBMS
home, but the fix is not correctly applied to the ASM HOME.

So either install that patch to the ASM HOME, or if that has been done
check why it failed.

A common reason for failure is a permission problem. Check bug 9711074
and its duplicates for more background. And check documentation bug 8629483
for the solution.

How do I know the fix is not missing? This error message is the key:
ORA-15061: ASM operation not supported [41]
(especially with operation 41)

If the patch was applied to the grid home, then probably the relink failed
due to permission problems.

ORA-15061: ASM Operation Not Supported [41] After Apply PSU #1 [ID 1126113.1]

pplies to:
Oracle Server – Enterprise Edition – Version: 11.2.0.1 and later [Release: 11.2 and later ]
Information in this document applies to any platform.
Symptoms
1) After apply PSU 1 (11.2.0.1.1 ) on the Grid Infrastructure Oracle Home
customer is unable to resize an ASM datafile:

SQL> alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560M;
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560M
*
ERROR at line 1:
ORA-1237: cannot extend datafile 4
ORA-1110: data file 4: ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
ORA-17505: ksfdrsz:1 Failed to resize file to size 71680 blocks
ORA-15061: ASM operation not supported [41]

2) DB alertlog reports (alert_brg13ed1.log):

Mon Jun 07 11:27:57 2010
Stopping background process CJQ0
Mon Jun 07 12:30:28 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 536870915
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 536870915…
Mon Jun 07 13:07:40 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560m
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560m…
Mon Jun 07 13:49:50 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 800M
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 800M…
Mon Jun 07 13:58:51 2010
alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’
resize 560M
ORA-1237 signalled during: alter database datafile
‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560M…
Mon Jun 07 14:25:43 2010

3) ASM alert.log does not report any problem.

Changes
PSU 1 (11.2.0.1.1 ) patchset was installed on the Grid Infrastructure Oracle Home
Cause

The PSU #1 (11.2.0.1.1 ) patch on the Grid Infrastructure Oracle Home was not correctly linked by opatch.

The PSU #1 (11.2.0.1.1 ) patch on the Grid Infrastructure Oracle Home needs to be relinked.
Solution
Relink the PSU #1 patch on the Grid Infrastructure Oracle Home as follow:

1) Shutdown the database instances.

2) Shutdown the ASM instance.

3) Relink the Grid Infrastructure Oracle Home as follow:

script /tmp/relink_GI.txt

env | sort

$ORACLE_HOME/bin/relink all

exit

4) Startup the ASM instance.

5) Startup the databases.

6) Resize the datafile:

SQL> alter database datafile ‘+DATA/brg13ed/datafile/ts_brg_users.1279.711064345’ resize 560M;

该bug一般是由于对grid infrastructure实施了PSU 1 (11.2.0.1.1 )后,Oracle binary没有正确link导致的,可行的解决方案是relink all,但这需要重启instance!

沪ICP备14014813号-2

沪公网安备 31010802001379号