<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fans Or Not &#187; E-Business Suite</title>
	<atom:link href="http://www.orafans.net/category/ebs/feed" rel="self" type="application/rss+xml" />
	<link>http://www.orafans.net</link>
	<description>寒山问拾得</description>
	<lastBuildDate>Sun, 22 Aug 2010 02:48:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>EBS 11i升级到R12</title>
		<link>http://www.orafans.net/2010/07/ebs-11i-upgrade-r12.html</link>
		<comments>http://www.orafans.net/2010/07/ebs-11i-upgrade-r12.html#comments</comments>
		<pubDate>Mon, 05 Jul 2010 05:38:23 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=631</guid>
		<description><![CDATA[花了大概一周时间完成了一套11i系统(到12.1.1)的升级，之所以耗费如此多时间，简单归纳了一下大致有以下原因： 历史遗留的配置问题（比如用中文做关键词），此类问题导致数据转换错误。 客户化（索引，物化视图等）导致升级错误。 测试机性能差，耗时颇巨。期间多次由于内存的原因，导致java程序出错。 很多R12本身的升级过程中的bug需要处理。 部分业务数据升级时出错，可能是旧数据完整性被破坏所致。 一些前期工作跳过没错，这本来可以缩短升级过程的一部分排错时间。 其他的一些可在升级之前就预先解决的问题。 整体上说，机器的性能问题很关键，有些步骤运行动辄数个小时，有些是升级程序有优化余地而事先没有发现，这些一般都在metalink上有了解决办法。对于升级，很多人第一反应就是克隆环境升级，然后导入最新数据并进行主备切换，其实这种方案对于多数企业而言很难，因为升级过程中会修改大量的表结构，甚至很多应用级别的调整，我很怀疑有哪家公司能够做到对Oracle EBS的数据结构了解的如此洞彻明晰，至少国内没有。这是我第一次对11i进行升级，积累了一些经验，在此分享。 升级前的准备 升级前的准备包括三方面，一个是应用本身的准备工作，这个在升级手册里已经详细说明；另一个就是对服务器性能做一个充分的评估，确保整个升级过程不会跳到deadline之外；还有一个，就是将所有能提前做的工作都做好，比如invalid objects，韩语分词补丁，OLAP升级等等，这些在数据库升级阶段不是必须的，但是EBS升级时却是无法直接忽略的步骤，此外可靠的网络连接也很重要，patching过程中断线后虽然可以继续，但是光启动就要花不少时间。 升级过程中的注意事项 这里依旧按照升级步骤来进行说明。 Disable AOL Audit Trail (conditional) 关闭所有审计功能，包括标准功能提供的，以及客户自行在DB级别上添加的。 Shut down application tier listeners and concurrent managers (required) Migrate database to at least Oracle10g Release 2 (conditional) 这一步之前已经做了，考虑到停机时间，分两步走是比较合适的方案。 Update init.ora with upgrade parameters (required) 同上，升级数据库时已经基本做好了。 Disable custom triggers, constraints, and indexes (conditional) 注意：最好将所有直接关联到标准表的客户化索引和Materialized [...]]]></description>
			<content:encoded><![CDATA[<p>花了大概一周时间完成了一套11i系统(到12.1.1)的升级，之所以耗费如此多时间，简单归纳了一下大致有以下原因：</p>
<ol>
<li>历史遗留的配置问题（比如用中文做关键词），此类问题导致数据转换错误。</li>
<li>客户化（索引，物化视图等）导致升级错误。</li>
<li>测试机性能差，耗时颇巨。期间多次由于内存的原因，导致java程序出错。</li>
<li>很多R12本身的升级过程中的bug需要处理。</li>
<li>部分业务数据升级时出错，可能是旧数据完整性被破坏所致。</li>
<li>一些前期工作跳过没错，这本来可以缩短升级过程的一部分排错时间。</li>
<li>其他的一些可在升级之前就预先解决的问题。</li>
</ol>
<p>整体上说，机器的性能问题很关键，有些步骤运行动辄数个小时，有些是升级程序有优化余地而事先没有发现，这些一般都在metalink上有了解决办法。对于升级，很多人第一反应就是克隆环境升级，然后导入最新数据并进行主备切换，其实这种方案对于多数企业而言很难，因为升级过程中会修改大量的表结构，甚至很多应用级别的调整，我很怀疑有哪家公司能够做到对Oracle EBS的数据结构了解的如此洞彻明晰，至少国内没有。这是我第一次对11i进行升级，积累了一些经验，在此分享。</p>
<h3>升级前的准备</h3>
<p>升级前的准备包括三方面，一个是应用本身的准备工作，这个在升级手册里已经详细说明；另一个就是对服务器性能做一个充分的评估，确保整个升级过程不会跳到deadline之外；还有一个，就是将所有能提前做的工作都做好，比如invalid objects，韩语分词补丁，OLAP升级等等，这些在数据库升级阶段不是必须的，但是EBS升级时却是无法直接忽略的步骤，此外可靠的网络连接也很重要，patching过程中断线后虽然可以继续，但是光启动就要花不少时间。</p>
<h3>升级过程中的注意事项</h3>
<p>这里依旧按照升级步骤来进行说明。</p>
<ol>
<li>Disable AOL Audit Trail (conditional)<br />
关闭所有审计功能，包括标准功能提供的，以及客户自行在DB级别上添加的。</li>
<li>Shut down application tier listeners and concurrent managers (required)</li>
<li>Migrate database to at least Oracle10g Release 2 (conditional)<br />
这一步之前已经做了，考虑到停机时间，分两步走是比较合适的方案。</li>
<li>Update init.ora with upgrade parameters (required)<br />
同上，升级数据库时已经基本做好了。</li>
<li>Disable custom triggers, constraints, and indexes (conditional)<br />
注意：最好将所有直接关联到标准表的客户化索引和Materialized View都drop掉，这很可能和升级程序有冲突。比如客户化索引，很可能升级过程中就会创建同样的索引（不同名），也可能修改表结构，这些操作都可能引起错误。</li>
<li>Drop MRC schema (conditional)</li>
<li>Back up the database (recommended)</li>
<li>Ensure that Maintenance Mode is enabled (required)<br />
在11i环境中启用维护模式，如果数据被一些外部程序所用，则最好在升级期间停掉。</li>
<li>Apply AD 12.1.1 upgrade driver (required)<br />
先取消appltest的环境变量(.profile)，然后source新的APPS<SID>_host.env，该文件在新的$APPL_TOP目录下，如apps/apps_st/appl/APPSTEST_erptest.env。<br />
adpatch 时可能会报如下错误：</p>
<pre class="brush:text">
ld.so.1: adpatch: fatal: .../apps/tech_st/10.1.2/lib/libclntsh.so.10.1: wrong ELF class: ELFCLASS64
</pre>
<p>原因是如下错误所导致的：<br />
进 apps/tech_st/10.1.2/lib32 目录ls -l</p>
<pre class="brush:text">ldflags -> /d4/R12/ab/apps/R1211XB9/apps/tech_st/10.1.2/lib/ldflags</pre>
<p>ldflags链接到了一个不存在的文件上，这是R12本身的bug，解决办法：</p>
<pre class="brush:bash">
$ rm $ORACLE_HOME/lib32/ldflags
$ ln -s $ORACLE_HOME/lib/ldflags $ORACLE_HOME/lib32/ldflags
</pre>
<p>然后 $ORACLE_HOME/bin/genclntsh -32 重新生成libclntsh.so.10.1。<br />
注意：$ORACLE_HOME请指向10.1.3目录，否则在Post-Upgrade还得一番折腾。</li>
<li>Run the American English upgrade patch driver (required)<br />
这一步耗时最长，问题也最多。在我的测试环境中，因为机器内存小(有两套克隆环境)，patching 过程经常报java错误，需要留意检查adworkxxx.log日志，若发现错误可以尝试用adctrl去failed该job等待其重新处理即可通过。该步骤会把测试机拖得非常慢，每个adworker会带出一个java进程，占用内存非常大，所以将worker设定为一个比较小的数值会更好，比如8个，等之后运行sql等占用内存较少的步骤时，再将adworker数目调大。</p>
<p><strong>错误</strong>：</p>
<pre class="brush:sql">
CREATE OR REPLACE SYNONYM APPS.CST_ACCRUAL_ACCOUNTS FOR
	 BOM.CST_ACCRUAL_ACCOUNTS

	AD Worker error:
	The following ORACLE error:

	ORA-00955: name is already used by an existing object
</pre>
<p>同义词和一个视图名称一样了。这个错误很低级，我的解决办法是 DROP VIEW APPS.CST_ACCRUAL_ACCOUNTS。</p>
<p><strong>错误</strong>:</p>
<pre class="brush:text">
A database error occurred:
  ORA-24816: Expanded non LONG bind data supplied after actual LONG or LOB column

The error occurred while executing the following statement:
  INSERT INTO FND_SEED_STAGE_ENTITY (SEQ, CONFIG_ID, TOP_ENTITY_SEQ, LAST_DB_UPDATED_BY, LAST_DB_UPDATE_DATE, LAST_FILE_UPDATED_BY, LAST_FILE_UPDATE_DATE, ACTION, EXEC_STATUS, COMMIT_FLAG, BIND_VAR_METADATA, PARENT_PK_VALUE ,BIND_VALUE0 ,BIND_VALUE1 ,BIND_VALUE2 ,BIND_VALUE3 ,BIND_VALUE4 ,BIND_VALUE5 ,BIND_VALUE6,BIND_VALUE7 ,BIND_VALUE8 ,BIND_VALUE9 ,BIND_VALUE10 ,BIND_VALUE11 ,BIND_VALUE12 ,BIND_VALUE13 ,BIND_VALUE14 ,BIND_VALUE15 ,BIND_VALUE16 ,BIND_VALUE17 ,BIND_VALUE18 ,BIND_VALUE19 ,BIND_VALUE20 ,BIND_VALUE21 ,BIND_VALUE22 ,BIND_VALUE23 ,BIND_VALUE24 ,BIND_VALUE25 ,BIND_VALUE26 ,BIND_VALUE27 ,BIND_VALUE28 ,BIND_VALUE29 ,BIND_VALUE30) VALUES (:seq, :config_id, :top_entity_seq, NULL, NULL, NULL, NULL, 'IGNORE', '0', NULL, :bvar_metadata, :parent_pk_value ,:bind_value0 ,
	:bind_value1 ,:bind_value2 ,:bind_value3 ,:bind_value4 ,:bind_value5 ,:bind_value6 ,:bind_value7 ,:bind_value8 ,:bind_value9 ,:bind_value10 ,:bind_value11 ,:
	bind_value12 ,:bind_value13 ,:bind_value14 ,:bind_value15 ,:bind_value16 ,:bind_value17 ,:bind_value18 ,:bind_value19 ,:bind_value20 ,:bind_value21 ,:bind_va
	lue22 ,:bind_value23 ,:bind_value24 ,:bind_value25 ,:bind_value26 ,:bind_value27 ,:bind_value28 ,:bind_value29 ,:bind_value30)
</pre>
<p>旧的NLS_LANG是American_America.ZHS16GBK，新的NLS_LANG是American_America.UTF8（这是rapidwiz默认赋值的），如果在安装就设置NLS_LANG和旧的一致，则不会出现问题，但是也无法转换form等编码了。<br />
解决办法：用另一用户登录，修改NLS_LANG，手工执行fndload，然后adctrl用隐藏选项8来跳过该步骤。</p>
<p><strong>错误</strong>:<br />
如果升级数据库时没有升级OLAP，则会出现一个OLAP相关的错误，此时需要升级OLAP到64位。也可以通过重建AW来解决：</p>
<pre class="brush:sql">
exec dbms_aw.execute('aw delete zpb.zpbcode')
exec dbms_aw.execute('aw delete zpb.zpbdata')
exec dbms_aw.execute('aw delete zpb.zpbannot')
@appl_top/zpb/12.0.0/patch/115/SQL/zpbmakeaws.sql
</pre>
<p>Note:<br />
<strong>EPB AW&#8217;s Cannot Be Attached Or Do Not Exist [ID 795247.1]</strong></p>
<p><strong>错误4</strong>:<br />
eamsnupd.sql 步骤出错，此步进行前需要预先设置好Installed Base中相关参数和配置文件。<br />
Note:<br />
<strong>Enterprise asset Management (EAM) Upgrade Notes to R12 &#8211; Integration and Licence [ID 884201.1]</strong></p>
<p>注：自R12起，IB和eAM将紧密集成。Oracle 真应当将这部分内容写到升级文档中，不了解Installed Base就尝试升级是个悲剧。</p>
<p><strong>phase=A232 eamdffup.sql出错</strong>：</p>
<pre class="brush:text">
sqlplus -s APPS/***** @.../apps/apps_st/appl/eam/12.0.0/patch/115/sql/eamdffup.sql
DECLARE
*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "APPS.FND_FLEX_DSC_API", line 1626
ORA-06501: PL/SQL: program error
ORA-06512: at "APPS.FND_FLEX_DSC_API", line 298
ORA-01403: no data found
ORA-06512: at line 177
</pre>
<p>仔细检查问题sql，发现由以下数据引起的：</p>
<pre class="brush:sql">
SELECT *
  FROM fnd_descr_flex_contexts_tl f
 WHERE f.application_id = 426
   AND f.descriptive_flex_context_code IN ('PE', 'PG');
</pre>
<p>解决办法：将弹性域名称从中文（能源计量：电能/能源计量：气体）修改为英文。</p>
<p><strong>phase=A250 apilnupg.sql有严重的性能问题，1天都跑不完</strong><br />
解决办法：</p>
<pre class="brush:sql">create index AP_INVOICE_DISTRIBUTIONS_N25 on AP_INVOICE_DISTRIBUTIONS_ALL(PARENT_REVERSAL_ID);</pre>
<p>Note:<br />
<strong>R12 : Performance Issue While Runing apilnupg.sql (Upgrade to 12.1.1) [ID 942694.1]</strong></p>
<p><strong>phase=A260 appdstln.sql 报错</strong></p>
<pre class="brush:text">
sqlplus -s APPS/***** @.../apps/apps_st/appl/ap/12.0.0/patch/115/sql/appdstln.sql &#038;un_ap &#038;batchsize 7 16
DECLARE
*
ERROR at line 1:
ORA-01400: cannot insert NULL into
("AP"."AP_PAYMENT_HIST_DISTS"."INVOICE_DISTRIBUTION_ID")
ORA-06512: at line 38
</pre>
<p>解决办法：修改AP_PAYMENT_HIST_DISTS.INVOICE_DISTRIBUTION_ID 和 AP_PAYMENT_HIST_DISTS.AMOUNT 允许为空，找到那些为空的数据查明原因。正式环境升级时应当避免该情况发生。<br />
注：这其实不是真正意义上的“解决”办法，关键是找到哪些数据有问题，为什么有问题。</p>
<p><strong>phase=A322 csxruprf.sql 报错</strong></p>
<pre class="brush:text">
sqlplus -s APPS/***** @.../apps/apps_st/appl/cs/12.0.0/patch/115/sql/csxruprf.sql
DECLARE
*
ERROR at line 1:
ORA-20002: ORA-20001: -28102-ORA-28102: policy does not exist.
ORA-06512: at line 146
</pre>
<p>解决办法：</p>
<pre class="brush:sql">SELECT nvl(sr_agent_security, 'XXXX') FROM cs_system_options;</pre>
<p>如果查询结果为ANONE，那么它认为已经创建policy，此处只需要生效即可，而实际上系统中并未存在这些policy。通过手工执行相关sql，并跳过该job继续。</p>
<p><strong>phase=A327 FNDFFVGN 报错</strong></p>
<pre class="brush:text">
.../apps/apps_st/appl/fnd/12.0.0/bin/FNDFFVGN &#038;ui_apps 0 Y 2 401 'MTLL' 'MTL_ITEM_LOCATIONS_KFV' 'Y'
Log filename : .../apps/apps_st/appl/admin/TEST/log/l9017672.req

Report filename : .../apps/apps_st/appl/admin/TEST/out/o9017672.out
Segmentation Fault - core dumped

AD Worker error:
The above program failed with error code -117.
See the AD Worker log file and/or the program log file for details.
</pre>
<p>解决办法：这个只是编译弹性域，可以跳过该步骤，应用起来后重新编译弹性域。</li>
<li>Run the NLS upgrade patch driver (conditional)</li>
<p>	- 出错</p>
<pre class="brush:text">
FRM-30064: Unable to parse statement select upet.type_name EPC_type_name, upec.name category_name, upet.type_id, upec.category_id
from mgd_idencoding_category upec,
     mgd_idencoding_type upet
where upec.category_id = upet.category_id
and ((NVl(upet.partition_value,0)= 0 and upet.category_id = 1 ) or upet.category_id <> 1)
order by upec.category_id,type_name.
ORA-00942: table or view does not exist
Record Group EPC_RULE_RG
Form: WMSLABEL
FRM-30085: Unable to adjust form for output.
</pre>
<p>解决办法：这个用不到，当作成功继续下一步。<br />
	- 出错</p>
<pre class="brush:text">
.../apps/tech_st/10.1.2/bin/rwconverter userid=APPS/***** source=.../apps/apps_st/appl/xtr/12.0.0/reports/ZHS/XTRTMBLT.rdf dest=.../apps/apps_st/appl/admin/TEST/out/tmp001.rdf stype=rdffile dtype=rdffile overwrite=yes batch=yes compile_all=yes
ld.so.1: rwconverter: fatal: librw.so: open failed: No such file or directory
Killed

ERROR [code=-119] generating report "XTRTMBLT.rdf" from input file
.../apps/apps_st/appl/xtr/12.0.0/reports/ZHS/XTRTMBLT.rdf
</pre>
<p>是编译rdf的程序有问题，参考文档：<br />
<strong>On R12.1.1/Solaris Platform , Generating Oracle Reports Files failed on : " ld.so.1: rwconverter: fatal: librw.so: open failed: No such file or directory", How to get a Potential quick Solution ?. [ID 1067786.1]</strong></li>
<li>Apply latest product patches (required)</li>
<li>Synchronize NLS and American English product patches (conditional)</li>
<li>Disable Maintenance Mode (required)</li>
<li>Reset init.ora parameters (required)<br />
	数据库升级时已经做了</li>
<li>Back up Oracle E-Business Suite (recommended)</li>
</ol>
<p>标准功能的升级并不难，虽然中途有很多问题，但是整体上没有多大难度(事实上这世界上的事情只有烦的，没有难的)。最耗精力和时间的，估计反而是那些凌乱的客户化应用。在ERP项目实施过程中，虽然每个人都知道文档的重要性，但是数年下来，回过头来整理时，往往会发现很多文档消失不见，或者有文档但是形同于无。这些是应用升级后需要耗费时间的地方。</p>
<p>对于客户化应用的升级，没有标准答案。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/07/ebs-11i-upgrade-r12.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EBS 11i数据库升级(9i-&gt;10g)几点事项</title>
		<link>http://www.orafans.net/2010/06/ebs-11i-database-upgrade-9i-10g.html</link>
		<comments>http://www.orafans.net/2010/06/ebs-11i-database-upgrade-9i-10g.html#comments</comments>
		<pubDate>Wed, 09 Jun 2010 07:31:00 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=612</guid>
		<description><![CDATA[最近几日在评估和测试EBS的系统升级(11i升级到R12)，虽然官方的升级文档里介绍的比较详细了，但是依旧会出现一些容易疏忽的问题，这里做一些记录。这里并不是单纯的数据库升级，需要考虑EBS的特殊应用。对于升级方案，标准的有三种： 同时升级数据库和应用。 先升级数据库到10gR2，然后升级应用到R12。 先升级数据库到11gR2，然后升级应用到R12。 其中第2和第3种方案有点类似，都是将整个升级方案划分为两个阶段，只是数据库版本不同。实际上，从技术上看，第1种方案也是两步走，只是在应用层跳过一些过渡性的补丁直接升级到R12。 在数据库升级方面，升级路线主要有下面两种： 路线1: 9.2.0.6 -> 9.2.0.8 -> 11.2.0.1 如果是Solaris系统，则要求系统版本至少为 Solaris 10 Update 6。 路线2: 9.2.0.6 -> 10.2.0.1 -> 10.2.0.4 注：最新patchset是10.2.0.5，只是升级文档依旧停留在10.2.0.4。 从一般认识上讲，Oracle数据库在下一个大版本出来后，上一个版本才被认为是相对更稳定的，所以此处选择第二条路线。 数据库升级方式简单而言有以下几种： DBUA，直接通过图形化工具升级，这个最简单。 Manual，类似于上一种方式，只是手工进行各个步骤的升级操作。 Export/Import 有利于数据表的整理，重构数据库，比如修改字符集、数据文件、表空间参数等，在升级时间上，比DBUA和Manual两种方式都要长。 利用数据复制等技术，升级备用环境后再切换。 由于允许停机，并且暂无特殊的要求，所以这里使用DBUA做升级操作。 在升级之前，建议卸载statspack，并且先解决Invalid Objects的问题。此外，数据库升级后DBLINK需要重建，所以先准备相关重建脚本。下面按照文档步骤升级数据库9.2.0.6 至 10.2.0.4，每个步骤都列在下面，对几个步骤中需要额外关注的地方做了备注。 Verify software versions 检查现在软件版本，基本上应该不会有问题的，留意一下AD版本，最新版本是11i.AD.I.7，不过要求11i.AD.I.6就可以了。 Migrate to Oracle Portal 10g (conditional) Deregister the current database server (conditional) Update application tier [...]]]></description>
			<content:encoded><![CDATA[<p>最近几日在评估和测试EBS的系统升级(11i升级到R12)，虽然官方的升级文档里介绍的比较详细了，但是依旧会出现一些容易疏忽的问题，这里做一些记录。这里并不是单纯的数据库升级，需要考虑EBS的特殊应用。对于升级方案，标准的有三种：</p>
<ol>
<li>同时升级数据库和应用。</li>
<li>先升级数据库到10gR2，然后升级应用到R12。</li>
<li>先升级数据库到11gR2，然后升级应用到R12。</li>
</ol>
<p>其中第2和第3种方案有点类似，都是将整个升级方案划分为两个阶段，只是数据库版本不同。实际上，从技术上看，第1种方案也是两步走，只是在应用层跳过一些过渡性的补丁直接升级到R12。</p>
<p>在数据库升级方面，升级路线主要有下面两种：</p>
<ol>
<li>路线1: 9.2.0.6 -> 9.2.0.8 -> 11.2.0.1<br />
如果是Solaris系统，则要求系统版本至少为 Solaris 10 Update 6。</li>
<li>路线2: 9.2.0.6 -> 10.2.0.1 -> 10.2.0.4<br />
注：最新patchset是10.2.0.5，只是升级文档依旧停留在10.2.0.4。</li>
</ol>
<p>从一般认识上讲，Oracle数据库在下一个大版本出来后，上一个版本才被认为是相对更稳定的，所以此处选择第二条路线。</p>
<p>数据库升级方式简单而言有以下几种：</p>
<ol>
<li>DBUA，直接通过图形化工具升级，这个最简单。</li>
<li>Manual，类似于上一种方式，只是手工进行各个步骤的升级操作。</li>
<li>Export/Import<br />
有利于数据表的整理，重构数据库，比如修改字符集、数据文件、表空间参数等，在升级时间上，比DBUA和Manual两种方式都要长。</li>
<li>利用数据复制等技术，升级备用环境后再切换。</li>
</ol>
<p>由于允许停机，并且暂无特殊的要求，所以这里使用DBUA做升级操作。</p>
<p>在升级之前，建议卸载statspack，并且先解决Invalid Objects的问题。此外，数据库升级后DBLINK需要重建，所以先准备相关重建脚本。下面按照文档步骤升级数据库9.2.0.6 至 10.2.0.4，每个步骤都列在下面，对几个步骤中需要额外关注的地方做了备注。</p>
<ol>
<li>Verify software versions<br />
检查现在软件版本，基本上应该不会有问题的，留意一下AD版本，最新版本是11i.AD.I.7，不过要求11i.AD.I.6就可以了。</li>
<li>Migrate to Oracle Portal 10g (conditional)</li>
<li>Deregister the current database server (conditional)</li>
<li>Update application tier context file with new database listener port number (conditional)</li>
<li>Export OLAP analytical workspaces (conditional)</li>
<li>Prepare to create the 10.2.0 Oracle home<br />
设置ORACLE_HOME环境变量，如 export ORACLE_HOME=/u08/test/proddb/10.2.0</li>
<li>Install the base 10.2.0 software<br />
安装10gR2软件，不要选择升级现有数据库，因为要先打一些补丁。这个过程最后会写oraclehomproperties.xml，要保证对应目录有可写权限。比如我曾遭遇了这个错误<br />
inventory/ContentsXML/oraclehomproperties.xml (Permission denied).</li>
<li>Install Oracle Database 10g Products from the 10g Companion CD</li>
<li>Perform 10.2.0.4 patch set pre-installation tasks<br />
这是正常的打数据库补丁操作，留意几个环境变量的修改就可以了。如：</p>
<pre class="brush:text">
export PATH=$ORACLE_HOME/bin:$ORACLE_HOME/perl/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export PERL5LIB=$ORACLE_HOME/perl/lib:$ORACLE_HOME/perl/lib/site_perl:$PERL5LIB</pre>
</li>
<li>Perform 10.2.0.4 patch set installation tasks</li>
<li>Create nls/data/9idata directory</li>
<li>Apply additional 10.2.0.4 RDBMS patches</li>
<li>Shut down Applications server processes and database listener</li>
<li>Prepare to upgrade</li>
<li>Upgrade the database instance<br />
执行utlu102i.sql查看升级后的变动情况，然后执行DBMS_STATS.GATHER_SCHEMA_STATS 收集统计数据以加快升级速度。在升级的时候如果没有列出所需的ORACLE_HOME，则需要检查并整理一下oratab。</li>
<li>Modify initialization parameters<br />
对于sga_target等参数，最好先计算以下之前的SGA大小再设置，其余的参考文档设置即可。</li>
<li>Additional database configuration</li>
<li>Perform 10.2.0.4 patch set post-installation tasks</li>
<li>Install Oracle Data Mining and OLAP</li>
<li>Natively compile PL/SQL code (optional)</li>
<li>Fix Korean lexers<br />
升级韩语分词，对于简体中文用户不必进行。<br />
注意：如果将来需要升级EBS至R12，则这一步是必须的，否则升级过程中会出错：</p>
<pre class="brush:text">
Uploading from staging tables
  Error loading seed data for CS_KB_SOLN_CATEGORIES_VL:  CATEGORY_ID = 1,  ORA-29877: failed in the execution of the ODCIINDEXUPDATE routine
ORA-20000: Oracle Text error:
DRG-50857: oracle error in textindexmethods.ODCIIndexUpdate
ORA-20000: Oracle Text error:
DRG-10602: failed to queue DML change to column   for primary key
DRG-13201: KOREAN_LEXER is desupported
ORA-30576: ConText Option dictionary loading error
</pre>
</li>
<li>Import OLAP analytical workspaces (conditional)<br />
同上，如果将来需要升级EBS至R12，则这一步是必须的，稍微不同的时，到时可以不必做“升级”操作，而是直接删除重建：</p>
<pre class="brush:sql">
exec dbms_aw.execute('aw delete zpb.zpbcode');
exec dbms_aw.execute('aw delete zpb.zpbdata');
exec dbms_aw.execute('aw delete zpb.zpbannot');
sqlplus '/ as sysdba' @$APPL_TOP/zpb/12.0.0/patch/115/SQL/zpbmakeaws.sql
</pre>
</li>
<li>Start the new database listener (conditional) </li>
<li>Run adgrants.sql (conditional)</li>
<li>Grant create procedure privilege on CTXSYS</li>
<li>Implement and run AutoConfig<br />
先检查TNS_ADMIN变量是否指向新的路径，并检查listener.ora，看SID_LIST_TEST中是否已经添加了相应的SID，netca创建的listener.ora可能会缺少这个信息。<br />
这里尤其需要留意的是，adbldxml.pl 创建配置文件后，如果做adconfig.pl会报错：</p>
<pre class="brush:text">
Can't locate object method "runPipedCmd" via package "ADX::util::Sysutil" at /u08/test/proddb/10.2.0/appsutil/bin/adconfig.pl line 806.
</pre>
<p>这是由于PERL5LIB没有包含新的appsutil中的perl lib所致，手工加上再执行就可以了。<br />
afdbprf.sh 这一步还会报错：</p>
<pre class="brush:text">ORA-12504: TNS:listener was not given the SID in CONNECT_DATA</pre>
<p>手工执行可以通过，可能是afdbprf.sh 中传递变量有问题。</li>
<li>Gather statistics for SYS schema<br />
dbms_stats.gather_schema_stats这一步没有问题，但是执行dbms_stats.gather_fixed_objects_stats时会报错：</p>
<pre class="brush:text">
declare
*
ERROR at line 1:
ORA-00600: internal error code, arguments: [1350], [1], [13], [], [], [], [],
[]
ORA-06512: at "SYS.DBMS_STATS", line 13210
ORA-06512: at "SYS.DBMS_STATS", line 13517
ORA-06512: at "SYS.DBMS_STATS", line 14039
ORA-06512: at line 3
ORA-06512: at line 33</pre>
<p>这应该是个BUG，据说在11gR2中被修复了。</li>
<li>Re-create custom database links (conditional)<br />
升级之前就已经准备好了DBLINK的重建脚本，直接重建即可。</li>
<li>Re-create grants and synonyms</li>
<li>Apply Oracle Receivables patch</li>
<li>Restart Applications server processes (conditional)</li>
</ol>
<p>按标准步骤做完后，数据库成功升级到10.2.0.4，升级后需要留意以下事项：</p>
<ul>
<li>检查 .profile ，使用使用新的环境变量。</li>
<li>如果有快速启动脚本之类的，看是否指向了新的路径。</li>
<li>检查AutoConfig新创建的env文件，看PATH变量是否正确，删除指向旧数据库的路径。</li>
<li>用adadmin重新生成messages并编译包，否则Web页面登录可能会报错：
<pre class="brush:text">
oracle.apps.fnd.framework.OAException: Application: FND, Message Name: FND_GENERIC_MESSAGE. Tokens: MESSAGE = java.sql.SQLException: ORA-00003: Message 3 not found;  product=RDBMS; facility=ORA
ORA-06512: ? "SYS.DBMS_UTILITY", line 70
ORA-06512: ? line 1
</pre>
</li>
<li>最好转换SYSTEM表空间到Local Management。</li>
</ul>
<p>主要参考文档<br />
Database Preparation Guidelines for an E-Business Suite Release 12.1.1 Upgrade [ID 761570.1]<br />
Oracle Applications Release 11i with Oracle 10g Release 2 (10.2.0) [ID 362203.1]	</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/06/ebs-11i-database-upgrade-9i-10g.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关闭功能顾问的那些诊断模式</title>
		<link>http://www.orafans.net/2010/05/close-function-consultant-debug-trace.html</link>
		<comments>http://www.orafans.net/2010/05/close-function-consultant-debug-trace.html#comments</comments>
		<pubDate>Fri, 28 May 2010 14:20:41 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=600</guid>
		<description><![CDATA[相对于SAP而言，Oracle ERP的另一个显著特征或许就是大量的BUG和补丁吧，也或许正因为如此，Oracle ERP中的故障诊断越来越便捷，方式也越来越，有Server级的诊断（如Form Server），有DB级的诊断，也有功能级的诊断（输出程序步骤和关键业务数据）。对于Form/Report Server之类的故障诊断，通常有专门的技术顾问负责，多数情况下，功能顾问在Oracle Support的建议下也会进行各种形式的、针对各个模块和功能的诊断，有的记录在表里，有的形成日志文件，也有的直接显示在页面上。对于不影响用户操作的诊断，事后很容易就忘记了关闭，于是大量的五花八门的被遗弃的debug和trace偷偷占用着宝贵的系统资源。 通常，功能顾问们涉及的诊断功能可直接通过配置文件启用，主要有下面这些： FND：启用调试日志 启用日志。如果为否 (&#8216;N&#8217;)，则运行时不会进行记录和发出预警。 OE：调试 选择“是”以激活 Oracle 订单分录管理系统表单用户退出和并发程序中的调试信息 OE：调试跟踪 选择“是”以激活 oracle 订单分录管理系统并发程序的跟踪输出 OSO：启用调试消息 用于显示/隐藏调试消息的 Sales Online 配置文件 PA：调试模式 指明是否按调试模式运行项目会计管理系统报表和流程；在调试模式下运行时，线索会被打开，附加信息会打印至日志文件 PO：将调试工作流设置为“打开” 启用/禁用 PO 工作流调试模式 PO：启用对接收处理程序的 SQL 跟踪 启用数据库 SQL 跟踪，以便调试接收事务处理程序。 RCV：调试模式 如果将此模式设置为“是”，则将在日志文件中打印消息。 初始化 SQL 语句 &#8211; 自定义 初始化会话的自定义 SQL 语句 其中“初始化 SQL 语句 &#8211; 自定义”比较特殊，可以自行设置event。它的格式如： BEGIN fnd_ctl.fnd_sess_ctl('','','','TRUE','','ALTER SESSION SET TRACEFILE_IDENTIFIER=' [...]]]></description>
			<content:encoded><![CDATA[<p>相对于SAP而言，Oracle ERP的另一个显著特征或许就是大量的BUG和补丁吧，也或许正因为如此，Oracle ERP中的故障诊断越来越便捷，方式也越来越，有Server级的诊断（如Form Server），有DB级的诊断，也有功能级的诊断（输出程序步骤和关键业务数据）。对于Form/Report Server之类的故障诊断，通常有专门的技术顾问负责，多数情况下，功能顾问在Oracle Support的建议下也会进行各种形式的、针对各个模块和功能的诊断，有的记录在表里，有的形成日志文件，也有的直接显示在页面上。对于不影响用户操作的诊断，事后很容易就忘记了关闭，于是大量的五花八门的被遗弃的debug和trace偷偷占用着宝贵的系统资源。</p>
<p>通常，功能顾问们涉及的诊断功能可直接通过配置文件启用，主要有下面这些：</p>
<ul>
<li><strong>FND：启用调试日志</strong> 启用日志。如果为否 (&#8216;N&#8217;)，则运行时不会进行记录和发出预警。</li>
<li><strong>OE：调试</strong> 选择“是”以激活 Oracle 订单分录管理系统表单用户退出和并发程序中的调试信息</li>
<li><strong>OE：调试跟踪</strong> 选择“是”以激活 oracle 订单分录管理系统并发程序的跟踪输出</li>
<li><strong>OSO：启用调试消息</strong> 用于显示/隐藏调试消息的 Sales Online 配置文件</li>
<li><strong>PA：调试模式</strong> 指明是否按调试模式运行项目会计管理系统报表和流程；在调试模式下运行时，线索会被打开，附加信息会打印至日志文件</li>
<li><strong>PO：将调试工作流设置为“打开”</strong> 启用/禁用 PO 工作流调试模式</li>
<li><strong>PO：启用对接收处理程序的 SQL 跟踪</strong> 启用数据库 SQL 跟踪，以便调试接收事务处理程序。</li>
<li><strong>RCV：调试模式</strong> 如果将此模式设置为“是”，则将在日志文件中打印消息。</li>
<li><strong>初始化 SQL 语句 &#8211; 自定义</strong> 初始化会话的自定义 SQL 语句</li>
</ul>
<p>其中“初始化 SQL 语句 &#8211; 自定义”比较特殊，可以自行设置event。它的格式如：</p>
<pre class="brush:sql">
BEGIN fnd_ctl.fnd_sess_ctl('','','','TRUE','','ALTER SESSION SET TRACEFILE_IDENTIFIER=' || '''' ||'4269824.999' || '''' || ' EVENTS =' || '''' ||' 10046 TRACE NAME CONTEXT FOREVER, LEVEL 12 ' || '''');END;
</pre>
<p>其实就相当于每次开启会话时自动执行了类似如下的命令：</p>
<pre class="brush:sql">alter session set events='10046 trace name context forever, level 12' ;</pre>
<p>用下面的SQL可以查询到各个级别的配置文件设置情况：</p>
<pre class="brush:sql">
SELECT n.user_profile_option_name NAME,
       to_char(v.last_update_date, 'yyyy-mm-dd') "Last Updated",
       decode(v.level_id,
              10001,
              'Site',
              10002,
              'Application',
              10003,
              'Responsibility',
              10004,
              'User',
              10005,
              'Server',
              10007,
              'SERVRESP',
              'UnDef') level_set,
       decode(to_char(v.level_id),
              '10001',
              '',
              '10002',
              app.application_short_name,
              '10003',
              rsp.responsibility_key,
              '10005',
              svr.node_name,
              '10006',
              org.name,
              '10004',
              usr.user_name,
              '10007',
              'Serv/resp',
              'UnDef') "CONTEXT",
       v.profile_option_value VALUE
  FROM fnd_profile_options       p,
       fnd_profile_option_values v,
       fnd_profile_options_vl    n,
       fnd_user                  usr,
       fnd_application           app,
       fnd_responsibility        rsp,
       fnd_nodes                 svr,
       hr_operating_units        org
 WHERE p.profile_option_id = v.profile_option_id(+)
   AND p.profile_option_name = n.profile_option_name
   AND usr.user_id(+) = v.level_value
   AND v.level_id = 10004 -- User
   AND rsp.application_id(+) = v.level_value_application_id
   AND rsp.responsibility_id(+) = v.level_value
   AND app.application_id(+) = v.level_value
   AND svr.node_id(+) = v.level_value
   AND org.organization_id(+) = v.level_value
 ORDER BY n.user_profile_option_name,
          level_set;
</pre>
<p>对于懒人们，不妨做成自动预警，每周末检查一次就可以了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/05/close-function-consultant-debug-trace.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>计划管理器(Planning Manager)技术概要</title>
		<link>http://www.orafans.net/2010/05/planning-manager-tech-preview.html</link>
		<comments>http://www.orafans.net/2010/05/planning-manager-tech-preview.html#comments</comments>
		<pubDate>Thu, 27 May 2010 07:54:14 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=592</guid>
		<description><![CDATA[计划管理器简介 计划管理器属于Immediate类型的可执行并发程序，作为MRP 管理器的子例程运行。MRP 管理器是一种特殊的并发管理器，和计划管理器是完全不同的存在。它主要作用在以下几个方面： 针对发运冲减MDS 针对完工产品冲减MPS 预测冲减 MRP接口数据的处理 相关数据清理 实际上，计划管理器和相关的MPS/MRP冲减工作流程是通过下列存储过程完成的： MRP_MANAGER_PK 这个包里面的各个过程执行不同的任务。 MRP_UPDATE_MRP_INFO_PK.mrp_update_mrp_cols 该过程用于MPS Relief Worker MRP_AUTO_REDUCE_PK.mrp_auto_reduce_mps 该过程用于每日清理 计划管理器的启动 进入供应链管理员(Supply Chain Planner)职责，在设置菜单里有计划管理器的设置。 间隔时间是指计划管理器每次隔多久处理一次数据，它是指每次的开始时间的间隔长度，如果执行时间超过间隔时间，则执行结束后等待该时间后再次执行。若间隔时间太短，则可以近乎当作不间断执行，这时的冲减也是最及时的，但是系统资源消耗较大。同时，间隔时间过短，日志会更加大，如果启用了DEBUG模式，则每日的日志将可能多出数百兆(视业务数据多少有所不同)。 如果计划管理器处于Active状态，则设置窗口中的Messages界面会显示每次执行的时间。该界面仅仅告知每次的执行时间，并没有多大保留意义，可以安全删除。如果想停止计划管理器，则直接根据请求号取消相应的并发请求即可。需要留意的是，由于计划管理器是依附于MRP管理器执行的，因此在异常诊断时，应当先确认MRP管理器是正常运行的。 每次重新启动计划管理器时，都会自动提交“Planning Manager Worker (once-a-day tasks)”。每天，计划管理器都会分配一个新的请求号，开始新的请求号时，“Planning Manager Worker (once-a-day tasks)”工作流程也会被自动提交。这也是个并发程序（派生类型）， 该程序主要执行各类清理工作。其中，对于MRP相关接口表的清理，主要取决于配置文件 MRP:Interface Table History Days 设置的保留天数。涉及的MRP接口表包括： MRP_FORECAST_INTERFACE MRP_SCHEDULE_INTERFACE MRP_RELIEF_INTERFACE MRP_FORM_QUERY MRP_WORKBENCH_CRITERIA MRP_WORKBENCH_QUERY MRP_LOAD_PARAMETERS MDS Relief 创建新的订单时，会有记录插入到MTL_DEMAND，当发运确认后，相关记录会插入MTL_TRANSACTIONS_INTERFACE，接口数据被验证通过才会在MTL_MATERIAL_TRANSACTIONS产生新的纪录，在此同时，如果库存事务管理器判断出所处理的记录是销售订单，就会插入记录到MRP_RELIEF_INTERFACE以供冲减MDS。 在MRP_RELIEF_INTERFACE中的MDS待冲减条目的各字段含义如下： RELIEF_TYPE 为1 PROCESS_STATUS 为2，表示等待处理 DISPOSITION_ID [...]]]></description>
			<content:encoded><![CDATA[<p><strong>计划管理器简介</strong></p>
<p>计划管理器属于Immediate类型的可执行并发程序，作为MRP 管理器的子例程运行。MRP 管理器是一种特殊的并发管理器，和计划管理器是完全不同的存在。它主要作用在以下几个方面：</p>
<ol>
<li>针对发运冲减MDS</li>
<li>针对完工产品冲减MPS</li>
<li>预测冲减</li>
<li>MRP接口数据的处理</li>
<li>相关数据清理</li>
</ol>
<p>实际上，计划管理器和相关的MPS/MRP冲减工作流程是通过下列存储过程完成的：</p>
<ul>
<li>MRP_MANAGER_PK 这个包里面的各个过程执行不同的任务。</li>
<li>MRP_UPDATE_MRP_INFO_PK.mrp_update_mrp_cols 该过程用于MPS Relief Worker</li>
<li>MRP_AUTO_REDUCE_PK.mrp_auto_reduce_mps 该过程用于每日清理</li>
</ul>
<p><strong>计划管理器的启动</strong></p>
<p>进入供应链管理员(Supply Chain Planner)职责，在设置菜单里有计划管理器的设置。<br />
<a href="http://www.orafans.net/2010/05/planning-manager-tech-preview.html/2010-05-27_140954" rel="attachment wp-att-594"><img src="http://www.orafans.net/wp-content/uploads/2010/05/2010-05-27_140954.jpg" alt="" title="Planning Manager" width="600" height="398" class="alignnone size-full wp-image-594" /></a><br />
间隔时间是指计划管理器每次隔多久处理一次数据，它是指每次的开始时间的间隔长度，如果执行时间超过间隔时间，则执行结束后等待该时间后再次执行。若间隔时间太短，则可以近乎当作不间断执行，这时的冲减也是最及时的，但是系统资源消耗较大。同时，间隔时间过短，日志会更加大，如果启用了DEBUG模式，则每日的日志将可能多出数百兆(视业务数据多少有所不同)。</p>
<p>如果计划管理器处于Active状态，则设置窗口中的Messages界面会显示每次执行的时间。该界面仅仅告知每次的执行时间，并没有多大保留意义，可以安全删除。如果想停止计划管理器，则直接根据请求号取消相应的并发请求即可。需要留意的是，由于计划管理器是依附于MRP管理器执行的，因此在异常诊断时，应当先确认MRP管理器是正常运行的。</p>
<p>每次重新启动计划管理器时，都会自动提交“Planning Manager Worker (once-a-day tasks)”。每天，计划管理器都会分配一个新的请求号，开始新的请求号时，“Planning Manager Worker (once-a-day tasks)”工作流程也会被自动提交。这也是个并发程序（派生类型）， 该程序主要执行各类清理工作。其中，对于MRP相关接口表的清理，主要取决于配置文件 MRP:Interface Table History Days 设置的保留天数。涉及的MRP接口表包括：</p>
<ul>
<li>MRP_FORECAST_INTERFACE</li>
<li>MRP_SCHEDULE_INTERFACE</li>
<li>MRP_RELIEF_INTERFACE</li>
<li>MRP_FORM_QUERY</li>
<li>MRP_WORKBENCH_CRITERIA</li>
<li>MRP_WORKBENCH_QUERY</li>
<li>MRP_LOAD_PARAMETERS</li>
</ul>
<p><strong>MDS Relief</strong><br />
创建新的订单时，会有记录插入到MTL_DEMAND，当发运确认后，相关记录会插入MTL_TRANSACTIONS_INTERFACE，接口数据被验证通过才会在MTL_MATERIAL_TRANSACTIONS产生新的纪录，在此同时，如果库存事务管理器判断出所处理的记录是销售订单，就会插入记录到MRP_RELIEF_INTERFACE以供冲减MDS。</p>
<p>在MRP_RELIEF_INTERFACE中的MDS待冲减条目的各字段含义如下：</p>
<ul>
<li><strong>RELIEF_TYPE</strong> 为1</li>
<li><strong>PROCESS_STATUS</strong> 为2，表示等待处理</li>
<li><strong>DISPOSITION_ID</strong> 为MTL_DEMAND.DEMAND_ID</li>
</ul>
<p>对于MDS冲减，计划管理器仅仅处理符合以上条件的记录。</p>
<p><strong>MPS Relief</strong><br />
之前介绍过 <a href="http://www.orafans.net/2010/02/mps-relief-worker.html">MPS Relief Worker</a>，这里补充一下MPS冲减的数据来源。</p>
<p>当采购申请、采购订单、接收事务等采购相关数据产生时，会有记录插入到MTL_SUPPLY，这些数据都作为供应用于MPS冲减。当然离散任务的发放、完工时，会有记录插入到WIP_DISCRETE_JOBS，此时也会触发冲减。对于冲减记录的产生，在系统内部实际上是通过Trigger来实现的，大致有以下Trigger:</p>
<ul>
<li>MTL_SUPPLY_T 作用于表MTL_SUPPLY</li>
<li>WIP_DISCRETE_JOBS_BRI 作用于表WIP_DISCRETE_JOBS，针对新增离散任务</li>
<li>WIP_DISCRETE_JOBS_BRU 作用于表WIP_DISCRETE_JOBS，针对离散任务状态的修改</li>
<li>WIP_DISCRETE_JOBS_BRD 作用于表WIP_DISCRETE_JOBS，针对离散任务的删除</li>
</ul>
<p>在MRP_RELIEF_INTERFACE中的MPS待冲减条目的各字段含义如下：</p>
<ul>
<li><strong>RELIEF_TYPE</strong> 为2</li>
<li><strong>PROCESS_STATUS</strong> 为2，表示等待处理</li>
<li><strong>DISPOSITION_ID</strong> 为若来源于MTL_SUPPLY，则该字段视来源分别可能是REQ_HEADER_ID, SHIPMENT_HEADER_ID, PO_HEADER_ID，若来源于WIP_DISCRETE_JOBS，则该字段对应于WIP_ENTITY_ID。</li>
</ul>
<p><strong>相关的配置文件</strong></p>
<p>MRP:Interface Table History Days 接口数据保留日期，仅删除已完成的记录<br />
MRP:Planning Manager Batch Size 指定每个Worker的处理记录数量<br />
MRP:Planning Manager Max Workers 最大同时启动多少个Worker<br />
MRP:Perform Planning Manager Functions in Loads 让主计划程序执行计划管理器的相关功能<br />
MRP:Consume MDS 启用MDS冲减<br />
MRP:Consume MPS 启用MPS冲减<br />
MRP:Debug Mode 启用诊断模式，会在日志中输出运行过程中的相关信息<br />
MRP:Trace Mode DB级的诊断，Trace文件产生在USER_DUMP_DEST目录下</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/05/planning-manager-tech-preview.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Planning Manager诊断过程和10046事件</title>
		<link>http://www.orafans.net/2010/05/planning-manager-10046-event.html</link>
		<comments>http://www.orafans.net/2010/05/planning-manager-10046-event.html#comments</comments>
		<pubDate>Wed, 26 May 2010 08:37:46 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=560</guid>
		<description><![CDATA[在一次Planning Manager性能问题的诊断中，用到了Oracle ERP环境中非常典型的诊断操作和过程，特全程记录于此。 当发现某个程序存在性能问题时，首先当然是快速检查一下SESSION的相关信息，看看主要在执行或等待些什么： SELECT stat.sid, n.name, n.class, stat.value FROM v$sesstat stat, v$statname n WHERE stat.statistic# = n.statistic# AND stat.sid = 121 ORDER BY upper(n.name); 这里观察到bytes received via SQL*Net from client, bytes sent via SQL*Net to client 和 SQL*Net roundtrips to/from client 都在飙升。这对应了两个events：SQL*Net message to client和SQL*Net message from client，这两个事件数值大并不意味着网络状况不好，前者仅仅表示Oracle数据库将数据放入TCP send buffer的时间，而后者表示从客户端接收到反馈指令的时间，两者反映了SQL*Net和数据库之间的时间消耗，而不是网络传输的时间消耗。基于对系统架构的了解，排除SQL*Net的性能问题，那么两个事件预示了什么呢？ SELECT * FROM v$sess_io [...]]]></description>
			<content:encoded><![CDATA[<p>在一次Planning Manager性能问题的诊断中，用到了Oracle ERP环境中非常典型的诊断操作和过程，特全程记录于此。</p>
<p>当发现某个程序存在性能问题时，首先当然是快速检查一下SESSION的相关信息，看看主要在执行或等待些什么：</p>
<pre class="brush:sql">
SELECT stat.sid,
       n.name,
       n.class,
       stat.value
  FROM v$sesstat  stat,
       v$statname n
 WHERE stat.statistic# = n.statistic#
   AND stat.sid = 121
 ORDER BY upper(n.name);
</pre>
<p>这里观察到<strong>bytes received via SQL*Net from client</strong>, <strong>bytes sent via SQL*Net to client</strong> 和 <strong>SQL*Net roundtrips to/from client</strong> 都在飙升。这对应了两个events：<strong>SQL*Net message to client</strong>和<strong>SQL*Net message from client</strong>，这两个事件数值大并不意味着网络状况不好，前者仅仅表示Oracle数据库将数据放入TCP send buffer的时间，而后者表示从客户端接收到反馈指令的时间，两者反映了SQL*Net和数据库之间的时间消耗，而不是网络传输的时间消耗。基于对系统架构的了解，排除SQL*Net的性能问题，那么两个事件预示了什么呢？</p>
<pre class="brush:sql">
SELECT * FROM v$sess_io v WHERE v.sid = 61;
</pre>
<p>观察会话中的数据库读取情况，CONSISTENT_GETS 值在持续增长。结合上面SQL*Net的情况，大致可以判断出该程序在反复执行某个查询语句，每次获取的数据量很小但频率很高。我们知道，客户端在读取数据时，可能影响的因素有Array Fetch Size、SQL*Net中的SDU和数据库服务器每次读取的数据量，简单计算SQL*Net每次传输大致的数据量后将问题定位到SQL的性能问题上。</p>
<p>开始跟踪Planning Manager的全过程。Planning Manager 是一种特殊的并发程序(Immediate)，它直接依附于并发管理器MRP Manager执行。但是作为并发请求，它的常规诊断方式是一样的。如果有计划管理器在运行，则先停掉它，然后启用Trace：<br />
<a href="http://www.orafans.net/2010/05/planning-manager-10046-event.html/2010-05-26_134025" rel="attachment wp-att-559"><img src="http://www.orafans.net/wp-content/uploads/2010/05/2010-05-26_134025.png" alt="" title="2010-05-26_134025" width="600" height="401" class="alignnone size-full wp-image-559" /></a><br />
关于详细操作和Trace文件的查找可参考另一篇文章《<a href="/2008/05/trace-concurrent-request.html">跟踪(Trace)并发请求</a>》</p>
<p>进入MRP计划管理员设置界面，启动Planning Manager。对于其他独立的并发请求，可以直接手工提交。等待Planning Manager处理完预先准备的接口数据后，立即取消该请求，并取消Trace。</p>
<p>接下来就是对Trace文件的解读。对于并发请求的Trace，其实就是对应的一次10046事件(event)，该事件可简单分为以下四个级别：</p>
<ul>
<li><strong>Level 1</strong>: 跟踪SQL</li>
<li><strong>Level 4</strong>: Level 1 + 跟踪绑定变量</li>
<li><strong>Level 8</strong>: Level 1 + 跟踪等待事件</li>
<li><strong>Level 12</strong>: Level 4 + Level 8 (跟踪SQL, 绑定变量和等待事件)</li>
</ul>
<p>手工方式的话可通过下面的命令启用：</p>
<pre class="brush:sql">
alter session set events='10046 trace name context forever, level 8' ;
</pre>
<p>它和下面的命令类似：</p>
<pre class="brush:sql">ALTER SESSION SET SQL_TRACE = TRUE</pre>
<p>只是前一个命令，可以根据需要指定不同的level，比如此处的level 8，表示跟踪到SQL和等待事件，而不获取绑定变量的数据。也可以通过包DBMS_System来启用，例如：</p>
<pre class="brush:sql">
EXEC DBMS_System.Set_Sql_Trace_In_Session(sid, serial#, true );
EXEC DBMS_System.Set_Ev(sid, serial#, event, level, name);
</pre>
<p>在某些场合下，针对并发请求的跟踪可能会产生不止一个Trace文件，此时第一个Trace文件中会指明第二个Trace文件标识，如：</p>
<pre class="brush:text">
PARSE #41:c=0,e=565,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=19728618248238
EXEC #41:c=0,e=781,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=19728618249248
=====================
PARSING IN CURSOR #41 len=54 dep=1 uid=44 oct=42 lid=44 tim=19728618250006 hv=4121095646 ad='f7b931f8'
ALTER SESSION SET TRACEFILE_IDENTIFIER='XZB_CR8909488'
END OF STMT
PARSE #41:c=0,e=249,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=19728618250001

*** TRACE DUMP CONTINUES IN FILE
……/udump/test_ora_14443_XZB_CR8909488.trc ***
</pre>
<p>先来大致看一下Trace文件中都有些什么。</p>
<pre class="brush:text">
Dump file ……/udump/test_ora_14443.trc
Oracle9i Enterprise Edition Release 9.2.0.6.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.6.0 - Production
ORACLE_HOME = /u08/test/proddb/9.2.0
System name:	SunOS
Node name:	erptest
Release:	5.10
Version:	Generic_118833-03
Machine:	sun4u
Instance name: TEST
Redo thread mounted by this instance: 1
Oracle process number: 59
Unix process pid: 14443, image: oracle@erptest (TNS V1-V3)
</pre>
<p>这是文件头，显示了相关环境信息。接着往下翻，关键在具体某条SQL的执行情况上，如下：</p>
<pre class="brush:text">
=====================
PARSING IN CURSOR #75 len=332 dep=0 uid=44 oct=3 lid=44 tim=19728619902280 hv=3581312695 ad='f2b4eb00'
select count(*)  into :b0  from wip_requirement_operations wro ,mtl_system_items items where ((((((wro.inventory_item_id=items.inventory_item_id and wro.organization_id=items.organization_id) and items.bom_item_type=4) and wro.wip_entity_id=:b1) and wro.wip_supply_type=6) and wro.organization_id=:b2) and wro.inventory_item_id=:b3)
END OF STMT
PARSE #75:c=10000,e=2221,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=0,tim=19728619902273
EXEC #75:c=0,e=2841,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19728619905363
WAIT #75: nam='db file sequential read' ela= 6392 p1=66 p2=135783 p3=1
……
FETCH #74:c=0,e=1248,p=0,cr=36,cu=0,mis=0,r=0,dep=0,og=4,tim=19728777309437
WAIT #74: nam='SQL*Net message to client' ela= 6 p1=1952673792 p2=1 p3=0
WAIT #74: nam='SQL*Net message from client' ela= 338 p1=1952673792 p2=1 p3=0
EXEC #74:c=0,e=256,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19728777310344
WAIT #74: nam='SQL*Net message to client' ela= 1 p1=1952673792 p2=1 p3=0
WAIT #74: nam='SQL*Net message from client' ela= 205 p1=1952673792 p2=1 p3=0
EXEC #75:c=0,e=110,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19728777310795
WAIT #75: nam='SQL*Net message to client' ela= 2 p1=1952673792 p2=1 p3=0
FETCH #75:c=30000,e=26138,p=0,cr=2028,cu=0,mis=0,r=1,dep=0,og=4,tim=19728777336976
WAIT #75: nam='SQL*Net message from client' ela= 278 p1=1952673792 p2=1 p3=0
FETCH #74:c=0,e=749,p=0,cr=36,cu=0,mis=0,r=0,dep=0,og=4,tim=19728777338168
WAIT #74: nam='SQL*Net message to client' ela= 2 p1=1952673792 p2=1 p3=0
WAIT #74: nam='SQL*Net message from client' ela= 304 p1=1952673792 p2=1 p3=0
EXEC #74:c=0,e=112,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19728777338769
WAIT #74: nam='SQL*Net message to client' ela= 1 p1=1952673792 p2=1 p3=0
WAIT #74: nam='SQL*Net message from client' ela= 227 p1=1952673792 p2=1 p3=0
EXEC #75:c=0,e=272,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=19728777339533
WAIT #75: nam='SQL*Net message to client' ela= 7 p1=1952673792 p2=1 p3=0
FETCH #75:c=30000,e=27212,p=0,cr=2028,cu=0,mis=0,r=1,dep=0,og=4,tim=19728777366810
WAIT #75: nam='SQL*Net message from client' ela= 415 p1=1952673792 p2=1 p3=0
……
</pre>
<p>这里显示了cursor语句的执行情况，发现编号为#74和#75的语句执行次数非常多，并且间隔执行，每次execute速度很快，fetch消耗时间相对较多，每次读取后立即发送给客户端。（格式的解读参考附注）</p>
<p>由于无法查看源代码，也没有任何技术文档，所以这里，大胆猜测这两个语句在一个LOOP中执行的可能性非常大。Tkprof格式化后，迅速定位最耗时的那个步骤：</p>
<pre class="brush:text">
select count(*)  into :b0
from
 wip_requirement_operations wro ,mtl_system_items items where
  ((((((wro.inventory_item_id=items.inventory_item_id and wro.organization_id=
  items.organization_id) and items.bom_item_type=4) and wro.wip_entity_id=:b1)
   and wro.wip_supply_type=6) and wro.organization_id=:b2) and
  wro.inventory_item_id=:b3)

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.00          0          0          0           0
Execute   8890      0.89       0.92          0          0          0           0
Fetch     8890    223.66     231.45       1951   18028921          0        8890
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    17781    224.56     232.37       1951   18028921          0        8890

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 44  

Rows     Row Source Operation
-------  ---------------------------------------------------
   8890  SORT AGGREGATE
      0   NESTED LOOPS
   8890    TABLE ACCESS BY INDEX ROWID MTL_SYSTEM_ITEMS_B
   8890     INDEX UNIQUE SCAN MTL_SYSTEM_ITEMS_B_U1 (object id 18977994)
      0    TABLE ACCESS BY INDEX ROWID WIP_REQUIREMENT_OPERATIONS
61341000     INDEX RANGE SCAN WIP_REQUIREMENT_OPERATIONS_N1 (object id 18977444)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  db file sequential read                      1951        0.08         11.65
  SQL*Net message to client                    8891        0.00          0.03
  SQL*Net message from client                  8891        0.01          2.82
  latch free                                     19        0.01          0.12
</pre>
<p>到这里终于确定了主要问题所在，下一步就是对该语句进行优化。由于无法修改代码，因此只能从执行计划角度考虑。检查该语句的执行计划，仔细检查发现虽然利用了索引WIP_REQUIREMENT_OPERATIONS_N1，看上去很漂亮，但是仔细检查索引字段发现这是个组合索引，若走这个索引或导致大量的逻辑块读。到此，整个诊断过程也顺利结束了。</p>
<p>附Trace格式解读：</p>
<pre class="brush:text">
PARSING IN CURSOR
len	Length of SQL statement.
dep	Recursive depth of the cursor.
uid	Schema user id of parsing user.
oct	Oracle command type.
lid	Privilege user id.
ela	Elapsed time. 8i: in 1/1000th of a second, 9i: 1/1'000'000th of a second
tim	Timestamp.
hv	Hash id.
ad	SQLTEXT address (see?v$sqlarea?and?v$sqltext).

PARSE, EXEC or FETCH
#n	n = number of cursor
c	cpu time
e	elapsed time
p	physical reads
cr	consistant reads
cu	current mode reads
mis	miss in cache
r	rows processed
dep	recursive depth
og	optimizer goal
tim	time</pre>
<p>详见 <a href="http://www.adp-gmbh.ch/ora/misc/trace_file_format.html">http://www.adp-gmbh.ch/ora/misc/trace_file_format.html</a> </p>
<p>有用的链接：</p>
<ul>
<li>《<a href="http://www.informit.com/articles/article.aspx?p=30628">SQL*Net Performance Tuning Using Underlying Network Protocols</a>》</li>
<li>《<a href="http://blog.tanelpoder.com/2008/02/07/sqlnet-message-to-client-wait-gotcha/">SQL*Net message to client wait isn’t really what it’s thought to be</a>》</li>
</ul>
<p><strong>Update</strong><br />
2010-05-27 其实是可以看到源代码的，下一篇文章会详细阐述。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/05/planning-manager-10046-event.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>案例：主物料界面性能问题</title>
		<link>http://www.orafans.net/2010/04/poor-performance-master-item-screen.html</link>
		<comments>http://www.orafans.net/2010/04/poor-performance-master-item-screen.html#comments</comments>
		<pubDate>Tue, 06 Apr 2010 05:35:51 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=499</guid>
		<description><![CDATA[案例： 物料查询主界面(Master Item Screen)更新速度极慢，有时候需要数分钟才能保存。 诊断： 做Form Trace，诊断日志中可以发现下面一段SQL执行效率很低： Trace file: /……/udump/test_ora_16779_XZB.trc Sort options: fchela ******************************************************************************** count = number of times OCI procedure was executed cpu = cpu time in seconds executing elapsed = elapsed time in seconds executing disk = number of physical reads of buffers from disk query = number of buffers gotten for consistent [...]]]></description>
			<content:encoded><![CDATA[<p>案例：<br />
物料查询主界面(Master Item Screen)更新速度极慢，有时候需要数分钟才能保存。</p>
<p>诊断：<br />
做Form Trace，诊断日志中可以发现下面一段SQL执行效率很低：</p>
<pre class="brush:text">
Trace file: /……/udump/test_ora_16779_XZB.trc
Sort options: fchela
********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************

SELECT WTG_ROWID,ROWID
FROM
 DR$WAITING  WHERE WTG_CID = :b1  AND WTG_PID = :b2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      2      0.00       4.85          0          0          0           0
Fetch        2  68700.00   68223.81      30187      30398          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4  68700.00   68228.66      30187      30398          0           0

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 31     (recursive depth: 2)
</pre>
<p>DR$WAITING 是Oracle Text相关表之一，和DR$PENDING等一系列表一样，主要用于全文检索相关功能的正常运作。简单来讲，DR$PENDING用于索引同步，当同步完成时里面的记录会自动删除，如果同步过程中相关记录又被修改，则相关信息暂时存放于DR$WAITING。检查该表行数：</p>
<pre class="brush:sql">
SELECT COUNT(1) FROM dr$waiting;
SELECT COUNT(1) FROM dr$pending;
</pre>
<p>如果存在大量记录（比如百万级），通常意味着相关程序没有正常进行(同步)。针对EBS环境，Metalink 382809.1 中介绍了几个常规的用于清理无效记录的请求：</p>
<ol>
<li>Rebuild Help Search Index (AFLOBBLD)</li>
<li>JTF Item InterMedia Index Optimizing operation (JTFOPTI)
<ul>
<li>参数p_optimize_level: FAST|FULL</li>
<li>参数p_runtime: 数值，默认为最大</li>
</ul>
</li>
<li>JTF Item InterMedia Index Sync Operation (JTFSYNC)</li>
<li>MES InterMedia Index Optimizing operation (AMVOPTI)</li>
<li>MES InterMedia Index Sync Operation (AMVSYNC)</li>
<li>Knowledge Management Index Synchronization (CS_KB_SYNC_INDEX)</li>
<li>Rebuilding Intermedia Index for Task Names (JTFTKIMD)</li>
<li>Synchronize JTF_NOTES_TL_C1 index (JTF_NOTES_TL_C1_SYNC)</li>
</ol>
<p>对于全文索引而言，所谓同步即加入新的关键词，而优化则意味着清理过期、失效的关键词。如果以上并发请求执行完毕后在DR$PENDING依旧存在记录，则可以手工进行同步：</p>
<pre class="brush:sql">
SELECT du.username,
       idx.idx_name
  FROM ctxsys.dr$index idx,
       dba_users       du
 WHERE du.user_id = idx.idx_owner#
   AND EXISTS
 (SELECT NULL FROM ctxsys.dr$pending pnd WHERE pnd.pnd_cid = idx.idx_id)
</pre>
<p>如：</p>
<pre class="brush:sql">
SQL> exec ctx_ddl.sync_index('AMV.AMV_C_CHANNELS_DESC_CTX');
</pre>
<p>正常情况下，全部手工处理一遍后，DR$WAITING中记录数应该为0。从DBA角度，CTX_DDL包中有几个优化索引的Procedure，可以考虑定期执行优化程序(清理被删除的Term)。<br />
<span id="more-499"></span><br />
在本例中，尽管执行了以上步骤，并不意味着主物料查询界面的效率会有多大提升。由于高水印(High Water)的关系，查询DR$WAITING的速度并不会有多大提升。此时检查DR$WAITING中记录，当记录数为0时，进行TRUNCATE操作，该操作可以去除高水印对查询效率的影响。如果DR$WAITING中记录数不为0，对于DR$PENDING存在的记录，可以删除这些记录后重新同步：</p>
<pre class="brush:sql">
DELETE FROM dr$waiting
 WHERE EXISTS (SELECT 1
          FROM dr$pending
         WHERE dr$pending.pnd_cid = dr$waiting.wtg_cid
           AND dr$pending.pnd_pid = dr$waiting.wtg_pid
           AND dr$pending.pnd_rowid = dr$waiting.wtg_rowid)
</pre>
<p>(正常情况下，这些记录会被自动删除)</p>
<p>重新进入主物料界面，对操作做Trace后查看日志：</p>
<pre class="brush:text">
SELECT WTG_ROWID,ROWID
FROM
 DR$WAITING  WHERE WTG_CID = :b1  AND WTG_PID = :b2

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      2      0.00       4.04          0          0          0           0
Fetch        2      0.00       1.20          0          6          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       5.24          0          6          0           0

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 31     (recursive depth: 2)
</pre>
<p>Oracle Text极其相关表的信息可以参考《Text Application Developer&#8217;s Guide》和《Text Reference》。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/04/poor-performance-master-item-screen.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Loader Worker 和Sql*Loader 参数</title>
		<link>http://www.orafans.net/2010/03/loader-worker-sqlloader.html</link>
		<comments>http://www.orafans.net/2010/03/loader-worker-sqlloader.html#comments</comments>
		<pubDate>Thu, 25 Mar 2010 01:00:10 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=479</guid>
		<description><![CDATA[之前介绍过MRP技术概览，其中有一个过程便是Loader Worker(装入程序工作流程)，该过程实际上是通过Sql*Loader从操作系统数据文件中将数据加载到数据库中。而在主计划设置选项中，其中一项是设置Sql*Loader参数： 那么这些参数究竟是什么含义？我们又如何通过调整这些参数来优化Loader Worker的性能呢？ 先来观察Loader Worker，会发现其执行时有两个或三个参数，如： CTRL_FILE=/u08/test/prodcomn/admin/out/TEST/M1922497MRLD_ITEMS.ctl DATA_FILE=/u08/test/prodcomn/admin/out/TEST/M1922497MRLD_ITEMS.dat DISCARD_FILE=/u08/test/prodcomn/admin/out/TEST/M1922497MRLD_ITEMS.dis 其中CTRL_FILE和DATA_FILE是每个并发请求都会有的，DISCARD_FILE会在部分并发请求中存在，比如载入MRP_SYSTEM_ITEMS表数据时就有该参数。想要理解这些参数的含义，便要先了解Sql*Loader参数的含义。 Sql*Loader 参数有数十个，相关的有如下几个： CONTROL 该参数指定了一个决定Sql*Loader行为的配置文件，它决定了需要从哪个数据文件读取数据，载入到哪张表里，分别有哪些字段等等。对应于Loader Worker的参数CTRL_FILE。 DATA 该参数指定了数据来源，也就是从哪个数据文件中读取记录。指定的数据文件每行的数据往往有特定的格式，有特定的分隔符区分每个字段的值。对应于Loader Worker的参数DATA_FILE。 DISCARD 该参数指定了一个文件用于记录那些未被正常导入到数据库中的记录。对应于Load Worker的参数DISCARD_FILE。 BINDSIZE Sql*Loader分批从数据文件中读取记录并提交到数据库中，每批的大小是有限制。该参数决定了Sql*Loader从数据文件读取记录大小的上限，除了每次读取的记录数必须小于ROWS指定的数目外，大小上不得超过BINDSIZE所指定的数值。该参数计量单位是Byte。 ROWS (每次Commit的记录数) 在Conventional Path模式时，它限定了bind array最大记录数。在Direct Path模式时，它限定了保存之前从数据文件中读取的最大记录数。它的作用和BINDSIZE类似，只是一个限制了记录数，一个限制了记录大小。 READSIZE (读缓存大小) 该参数仅针对从数据文件载入数据的方式时有效，默认值为64k，最大值因系统平台各有不同。在Conventional Path模式时，bind array 受限于读缓存，也就是说，在系统内存和bind array足够大的前提下，如果读缓存越大，则可以有更多的记录在commit前被读取，这也就意味着载入性能越好。当READSIZE小于BINDSIZE时，则READSIZE会被自动加大。 上述参数中，BINDSIZE和ROWS对应于Sql*Loader参数设置界面的相应字段，其他参数则对应于并发请求的相应参数。 在执行时，Sql*Loader会先将数据读取到bind array，然后一次性insert到表中并commit，关于Sql*Loader的具体工作原理，可以另行写一篇文章叙述，简单了讲，就是说多数情况下（可用的连续内存空间够大），两个参数越大，意味着更少的Commit次数，更高的效率（当然，这也不是绝对的，只是简单这么一说），所以从性能优化角度看，要确定调整这两个参数以在相应的环境中达到最优。对于数据行数量和大小的关系，可以用以下公式来计算： bind array 大小= ROWS * (固定宽度字段长度之和 + 可变长度字段最大长度之和 + ( 可变长度字段数 * 字段分割符长度) ) 虽然公式看着简单，但是针对具体情况计算起来却也繁琐。有一个简单的方式可以大致获取所需信息： 1. [...]]]></description>
			<content:encoded><![CDATA[<p>之前介绍过<a href="/2009/08/mrp-tech-preview.html">MRP技术概览</a>，其中有一个过程便是Loader Worker(装入程序工作流程)，该过程实际上是通过Sql*Loader从操作系统数据文件中将数据加载到数据库中。而在主计划设置选项中，其中一项是设置Sql*Loader参数：<br />
<a href="http://www.orafans.net/2010/03/loader-worker-sqlloader.html/mrpsqldr" rel="attachment wp-att-480"><img src="http://www.orafans.net/wp-content/uploads/2010/03/MRPSQLDR.png" alt="" title="MRPSQLDR" width="500" height="354" class="alignnone size-full wp-image-480" /></a><br />
那么这些参数究竟是什么含义？我们又如何通过调整这些参数来优化Loader Worker的性能呢？</p>
<p>先来观察Loader Worker，会发现其执行时有两个或三个参数，如：</p>
<ol>
<li>CTRL_FILE=/u08/test/prodcomn/admin/out/TEST/M1922497MRLD_ITEMS.ctl</li>
<li>DATA_FILE=/u08/test/prodcomn/admin/out/TEST/M1922497MRLD_ITEMS.dat</li>
<li>DISCARD_FILE=/u08/test/prodcomn/admin/out/TEST/M1922497MRLD_ITEMS.dis</li>
</ol>
<p>其中CTRL_FILE和DATA_FILE是每个并发请求都会有的，DISCARD_FILE会在部分并发请求中存在，比如载入MRP_SYSTEM_ITEMS表数据时就有该参数。想要理解这些参数的含义，便要先了解Sql*Loader参数的含义。</p>
<p>Sql*Loader 参数有数十个，相关的有如下几个：</p>
<ul>
<li><strong>CONTROL</strong><br />
该参数指定了一个决定Sql*Loader行为的配置文件，它决定了需要从哪个数据文件读取数据，载入到哪张表里，分别有哪些字段等等。对应于Loader Worker的参数CTRL_FILE。</li>
<li><strong>DATA</strong><br />
该参数指定了数据来源，也就是从哪个数据文件中读取记录。指定的数据文件每行的数据往往有特定的格式，有特定的分隔符区分每个字段的值。对应于Loader Worker的参数DATA_FILE。</li>
<li><strong>DISCARD</strong><br />
该参数指定了一个文件用于记录那些未被正常导入到数据库中的记录。对应于Load Worker的参数DISCARD_FILE。</li>
<li><strong>BINDSIZE</strong><br />
Sql*Loader分批从数据文件中读取记录并提交到数据库中，每批的大小是有限制。该参数决定了Sql*Loader从数据文件读取记录大小的上限，除了每次读取的记录数必须小于ROWS指定的数目外，大小上不得超过BINDSIZE所指定的数值。该参数计量单位是Byte。</li>
<li><strong>ROWS</strong> (每次Commit的记录数)<br />
在Conventional Path模式时，它限定了bind array最大记录数。在Direct Path模式时，它限定了保存之前从数据文件中读取的最大记录数。它的作用和BINDSIZE类似，只是一个限制了记录数，一个限制了记录大小。</li>
<li><strong>READSIZE</strong> (读缓存大小)<br />
该参数仅针对从数据文件载入数据的方式时有效，默认值为64k，最大值因系统平台各有不同。在Conventional Path模式时，bind array 受限于读缓存，也就是说，在系统内存和bind array足够大的前提下，如果读缓存越大，则可以有更多的记录在commit前被读取，这也就意味着载入性能越好。当READSIZE小于BINDSIZE时，则READSIZE会被自动加大。</li>
</ul>
<p>上述参数中，BINDSIZE和ROWS对应于Sql*Loader参数设置界面的相应字段，其他参数则对应于并发请求的相应参数。<br />
<span id="more-479"></span><br />
在执行时，Sql*Loader会先将数据读取到bind array，然后一次性insert到表中并commit，关于Sql*Loader的具体工作原理，可以另行写一篇文章叙述，简单了讲，就是说多数情况下（可用的连续内存空间够大），两个参数越大，意味着更少的Commit次数，更高的效率（当然，这也不是绝对的，只是简单这么一说），所以从性能优化角度看，要确定调整这两个参数以在相应的环境中达到最优。对于数据行数量和大小的关系，可以用以下公式来计算：</p>
<blockquote><p>bind array 大小= ROWS  * (固定宽度字段长度之和 + 可变长度字段最大长度之和 + ( 可变长度字段数   * 字段分割符长度) )</p></blockquote>
<p>虽然公式看着简单，但是针对具体情况计算起来却也繁琐。有一个简单的方式可以大致获取所需信息：<br />
1. 观察MRP运行过程，在Loader Worker这一步时根据参数备份对应的CONTROL文件和数据文件。<br />
2. 根据CONTROL文件里面所指定表，创建一个相同结构的表。<br />
3. 修改CONTROL文件，将表名和数据文件修改为之前备份的文件名。例：</p>
<pre class="brush:text">
OPTIONS (BINDSIZE=1000000, ROWS=1000, SILENT=(FEEDBACK,DISCARDS))
LOAD DATA
INFILE 'test.dat'
APPEND
INTO TABLE APPS.TEST_TBL

FIELDS TERMINATED BY '|' # 是个特殊字段，会导致feedproxy无法显示
(
inventory_item_id,
 organization_id,
description nullif( description ='-23453'),
 category_id nullif( category_id ='-23453'),
……
LAST_UPDATE_DATE SYSDATE,
CREATION_DATE SYSDATE
)
</pre>
<p>4. 运行Sql*Loader，增加参数LOG，将过程日志记录下来。</p>
<pre class="brush:bash">bash-3.00$ sqlldr userid=apps/apps_pwd control=test.ctl log=test.log</pre>
<p>5. 查看日志文件，可看到以下关键信息：</p>
<pre class="brush:text">
SQL*Loader: Release 8.0.6.3.0 - Production on Thu Mar 25 08:28:17 2010

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Control File:   test.ctl
Data File:      test.dat
  Bad File:     test.bad
  Discard File:  none specified

 (Allow all discards)

Number to load: ALL
Number to skip: 0
Errors allowed: 50
Bind array:     1000 rows, maximum of 1000000 bytes #这里是Sql*Loader参数设置的
Continuation:    none specified
Path used:      Conventional
Silent options: FEEDBACK and DISCARDS

……

Table APPS.TEST_TBL:
  406082 Rows successfully loaded.
  0 Rows not loaded due to data errors.
  0 Rows not loaded because all WHEN clauses were failed.
  0 Rows not loaded because all fields were null.

Space allocated for bind array:                 992880 bytes(60 rows) #达到了BINDSIZE上限
Space allocated for memory besides bind array:        0 bytes

Total logical records skipped:          0
Total logical records read:        406082
Total logical records rejected:         0
Total logical records discarded:        0

Run began on Thu Mar 25 08:28:17 2010
Run ended on Thu Mar 25 08:30:27 2010

Elapsed time was:     00:02:10.51
CPU time was:         00:01:21.52
</pre>
<p>平均每一行需要空间 992880/60 ~= 16548 Bytes ~= 16.16 K，再增加一行就超出了BINDSIZE所限1000000，所以这里每次最多只允许读取60行记录。</p>
<p>调整这两个参数，将BINDSIZE设置为165480000，ROWS设置为10000，重新运行Sql*Loader:</p>
<pre class="brush:text">
Space allocated for bind array:               165480000 bytes(10000 rows)
Space allocated for memory besides bind array:        0 bytes

Total logical records skipped:          0
Total logical records read:        406082
Total logical records rejected:         0
Total logical records discarded:        0

Run began on Thu Mar 25 08:56:22 2010
Run ended on Thu Mar 25 08:58:12 2010

Elapsed time was:     00:01:50.49
CPU time was:         00:01:26.52
</pre>
<p>这里，根据每行记录的大小，结合实际系统情况，就可以调整BINDSIZE和ROWS到一个更合适的数值了。当然，多数情况下，保持默认值即可，并没有多少调整的必要。</p>
<p>关于Sql*Loader的载入方式，有Conventional Path和Direct Path两种模式，由配置文件<strong>MRP:Use Direct Load Option</strong>控制，修改为Direct Path模式或许会发现执行速度快了不少，但是强烈不建议采用这种模式。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/03/loader-worker-sqlloader.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MPS Relief Worker</title>
		<link>http://www.orafans.net/2010/02/mps-relief-worker.html</link>
		<comments>http://www.orafans.net/2010/02/mps-relief-worker.html#comments</comments>
		<pubDate>Thu, 04 Feb 2010 05:12:03 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/?p=451</guid>
		<description><![CDATA[mps-relief-worker]]></description>
			<content:encoded><![CDATA[<p>MPS计划的冲减主要通过MPS Relief Worker (MPS 冲减工作流程)进行，如有异常，则将导致MPS数量无法冲减，计划不准。作为Oracle ERP的核心功能之一，程序方面自然经过了诸多考验，然而在实际工作环境中，却依然会出现问题。这种问题，或许来自异常的数据量，也可能出在服务器性能上。MPS计划冲减说白了是一件很简单的事情，就是在需要冲减的环节，比如在下达离散任务或创建采购订单等特定事件发生时，系统会自动对比需求数量，并作相应冲减。在技术实现上是如下进行的：</p>
<ol>
<li>指定事件（如创建采购订单）发生</li>
<li>触发器将数据插入接口 MRP_RELIEF_INTERFACE</li>
<li>MPS 冲减工作流程处理接口数据</li>
</ol>
<p>由于计划管理器的存在，可以保证数据被及时处理。计划管理器其中一个重要的步骤就是由MPS 冲减工作流程处理接口数据，实现冲减逻辑。但是有些时候，却发现系统总是出现很多的意外，比如可能找到这些错误：</p>
<pre class="brush:text">
mrupwj_update_wip_jobs 中出现 ORACLE 错误 1555

原因：由于 ORA-01555: snapshot too old: rollback segment number 2 with name "_SYSSMU2$" too small
ORA-06512: at "APPS.MRP_UPDATE_MRP_INFO_PK", line 284
ORA-06512: at line 1
, mrupwj_update_wip</pre>
<p>或</p>
<pre class="brush:text">
mrupwj_update_wip_jobs 中出现 ORACLE 错误 1652

原因：由于 ORA-01652: unable to extend temp segment by 128 in tablespace TEMP
ORA-06512: at "APPS.MRP_UPDATE_MRP_INFO_PK", line 284
ORA-06512: at line 1
, mrupwj_update_wip_jobs 失败。</pre>
<p>一方面，是因为DB配置的原因，另一方面，也是程序本身的问题。但是作为实施人员，这两块都无法改动，则只好对症下药，以其他方式来避免此类不是问题的问题了。</p>
<p>对于计划管理在冲减方面的逻辑，处理步骤上大致可以分为以下三步：</p>
<p><strong>Step 1</strong><br />
取所有PROCESS_STATUS=2，并且REQUEST_ID为空的记录，将PROCESS_STATUS标记为3，同时将REQUEST_ID标记为处理的冲减流程请求ID。可以通过以下SQL观察哪些待处理数据：</p>
<pre class="brush:sql">
SELECT *
  FROM mrp_relief_interface rel1
 WHERE inventory_item_id IN
       (SELECT inventory_item_id
          FROM mrp_relief_interface rel2
         WHERE rel2.request_id IS NULL
           AND rel2.error_message IS NULL
           AND rel2.relief_type = 2
           AND rel2.process_status = 2
           AND rownum <= 500
           AND inventory_item_id NOT IN
               (SELECT DISTINCT inventory_item_id
                  FROM mrp_relief_interface rel2
                 WHERE rel2.request_id IS NOT NULL
                   AND rel2.error_message IS NULL
                   AND rel2.relief_type = 2
                   AND rel2.process_status = 3))
   AND rel1.request_id IS NULL
   AND rel1.error_message IS NULL
   AND rel1.relief_type = 2
   AND rel1.process_status = 2;
</pre>
<p>REQUEST_ID先为计划管理器的并发请求ID，如果需要由MPS冲减工作流程来处理，则更新为新请求的ID。</p>
<p><strong>Step 2</strong><br />
MPS 冲减工作流程在处理时，会根据配置文件预设值确定数量和方式。相关配置文件如下：</p>
<ol>
<li>MRP:Consume MPS (MRP：冲减 MPS)<br />
是否冲减MPS，设置为是</li>
<li>MRP:Planning Manager Batch Size MRP：计划管理器批量<br />
每次处理接口数据的数量，建议值为500。最好不要超过1000</li>
<li>MRP:Planning Manager Max Workers MRP：计划管理器最大工作进程数<br />
在设置批量大小时，每个MPS冲减流程只处理对应数量的记录，因而如果接口数据量较大，会同时出现多个并发。该配置文件就是用于限制最大并发数量的。</li>
</ol>
<p>计划管理器也会处理PROCESS_STATUS=3的数据，但是这里的批数量只约束MPS冲减工作流程。</p>
<p><strong>Step 3</strong><br />
如果第二步正常处理，则接口数据会被标志为PROCESS_STATUS=5。Planning Manager启动时，会检查接口数据，并启动Planning Manager Worker (once-a-day tasks)，该请求会定期清理接口表中PROCESS_STATUS=5的数据。保留的时间范围由配置文件 MRP:Interface Table History Days 决定，默认是5天。</p>
<p>如果出现异常，则异常消息会记录在ERROR_MESSAGE，同时将PROCESS_STATUS标记为4。具体处理措施因事而异，如果需要重新处理，则必须先重置状态：</p>
<pre class="brush:sql">
UPDATE mrp_relief_interface m
   SET process_status = 2,
       request_id     = NULL,
       error_message  = NULL
 WHERE m.relief_type = 2
   AND m.process_status = 4;
</pre>
<p>不要一次性更新太多数据，最好在配置文件 MRP:Planning Manager Batch Size 的数量范围内，分批次进行。在处理时，需要先停止计划管理器，修改完毕后再重新启动计划管理器。</p>
<p>下面的SQL可以检查接口表中各类数据的数量：</p>
<pre class="brush: sql">
SELECT organization_id,
       SUM(decode(process_status, 1, 1, 0)) status1, --Do not process
       SUM(decode(process_status, 2, 1, 0)) status2, --Waiting to be Processed
       SUM(decode(process_status, 3, 1, 0)) status3, --In Process
       SUM(decode(process_status, 4, 1, 0)) status4, --Error
       SUM(decode(process_status, 5, 1, 0)) status5 --Successful completion
  FROM mrp_relief_interface
 GROUP BY organization_id;
</pre>
<p>需要留意的时，如果在功能逻辑范围内的错误，并不影响整个MPS冲减流程继续下去，但是如果是其他错误，如回滚段不足、快照陈旧等，会令MPS冲减工作流程挂起。在整个流程中，是根据并发请求状态来判断步骤是否完成的，因而可采取的措施是可以尝试手工修改并发请求状态，然后下一步继续执行。这种操作的后果就是冲减数量不正确。也可以先停止整个流程，待问题修正后重新启动MPS。</p>
<p>每次手工启动MPS计划流程时，都必须先执行MPS Relief Worker，就是为了保证计划数量的正确。而该程序正常执行的前提，就是接口中不应存在太多的数据。整个主计划的性能，由此可见一斑。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/02/mps-relief-worker.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EBS的后台执行方式</title>
		<link>http://www.orafans.net/2010/01/ebs-background-process.html</link>
		<comments>http://www.orafans.net/2010/01/ebs-background-process.html#comments</comments>
		<pubDate>Thu, 28 Jan 2010 03:35:27 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.net/2010/01/ebs%e7%9a%84%e5%90%8e%e5%8f%b0%e6%89%a7%e8%a1%8c%e6%96%b9%e5%bc%8f.html</guid>
		<description><![CDATA[ebs-background-process]]></description>
			<content:encoded><![CDATA[<p>在应用中，应当避免执行一些长时间运行的操作，毕竟对于一个OLTP环境，快速响应才是重心。在某些情况下，可能无法使用批处理的方案，需要在用户界面做操作，但是某些特殊环节可以后台运行。这时候，在设计功能时就应当考虑异步处理机制，尤其是要用好批处理和后台处理等方式。</p>
<p>对于后台处理方式，EBS中大致有这么几种方式可选：</p>
<ol>
<li>并发请求<br />
并发请求几乎可以实现任何耗时的运算，也是在EBS环境中常用的后台处理方式。比如很多地方都允许设置处理方式，如联机处理、后台处理等。根据系统性能和响应要求自行组合逻辑块。这种方式的优点是实现简单，管理方便，缺点是受限于并发管理器的配置。此外，大多数企业里的并发程序都运行在数据库服务器上，如果涉及到异构系统的数据传递需要考虑到安全方面的问题。</li>
<li>工作流 (Oracle Workflow)<br />
如果是逻辑判断比较清晰又比较复杂的话，这是不错的候选方案，实施顾问也可以非常清晰的看到各个流程走向。这个方式的优点是可以将运算逻辑模块化，缺点是偏长于逻辑判断，而不适用于大数据量运算。</li>
<li>业务事件 (Business Event)<br />
业务事件依托于Oracle Workflow，允许客户自行订阅并执行客户化代码。业务事件底层用到了AQ，可以将消息从数据库层传递到应用层。这也是我最欣赏的一块内容。EBS内置了很多标准的事件，比如付款、BOM更新、资产转移等。这种方式的优点是代码都在应用层执行，管理方式简单，缺点是标准的业务事件数量太少了。</li>
<li>DBMS_JOB<br />
这其实算是一种非标准的方式，但是对于客户化应用比较合适。有时候，使用并发请求和业务事件都太过麻烦，但是通过JOB可以非常迅速的剥离执行逻辑，对用户而言，这可以算是比较标准的后台处理方式。这种方式的优点是简单方便，缺点是适用范围有限，适合在数据库层的运算。</li>
<li>管道 (PIPE)<br />
Oracle数据库管道技术在EBS系统中，我目前只发现MRP运算时有用到。它在应付多程序间通讯方面有优势，一个极端的应用是你可以在操作系统shell中实时看到某并发请求的运行情况。它的实现逻辑简单来讲，就是一个会话将消息发送的缓冲区，另一个会话从消息缓冲区读取消息。这种方式的优点是通讯方便，缺点是可能需要自行设计多会话间的消息封装机制，并且仅适用于小数据量传递。</li>
<li>高级队列(AQ)<br />
EBS中很多异步处理机制都利用了AQ，这相对而言太过于“底层”了，很少在二次开发领域有用到的。在大型的客户化应用中用的较多。</li>
</ol>
<p>简单来看，对于后台处理方式就以上这么几种了。EBS R12中内置了SOA，可以通过外部平台进行运算，但是我不认为这是EBS系统范畴了。</p>
<p>个人比较推荐的是使用JOB，这在我的经验中是最简单有效的，不过前提是需要自行设计一套错误处理机制。如果涉及异构系统，我优先考虑业务事件。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/01/ebs-background-process.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用EBS日志功能</title>
		<link>http://www.orafans.net/2010/01/ebs-log.html</link>
		<comments>http://www.orafans.net/2010/01/ebs-log.html#comments</comments>
		<pubDate>Sat, 09 Jan 2010 07:26:45 +0000</pubDate>
		<dc:creator>Zeeno</dc:creator>
				<category><![CDATA[E-Business Suite]]></category>

		<guid isPermaLink="false">http://www.orafans.org/?p=448</guid>
		<description><![CDATA[目前，EBS系统中存在多种日志记录方式，有用于PL/SQL的，有用于Java的，有OAF等开发框架自带的，也有Forms Server之类服务器专用的诊断方式。通常来讲，所有二次开发，为了统一规范和便于管理，应当将将客户化系统中日志记录和Oracle EBS中的日志记录进行整合，用统一的方式进行日志记录和诊断。 Oracle EBS调试日志级别 系统中将调试日志级别分为6个级别，分别是： Type Level Description UNEXPECTED 6 未知异常 ERROR 5 错误 EXCEPTION 4 异常 EVENT 3 事件 PROCEDURE 2 过程 STATEMENT 1 语句，该级别最低，记录的日志信息也最详细。 该级别通过配置文件 FND：调试日志级别 控制。 调试日志模块 日志必须指定当前所执行的程序，也就是所谓的模块。模块用于区分不用程序产生的日志，比如我的一套用于将EBS事件通过手机短消息发送出去的整套程序统一定义成日志模块：oracle.apps.cux.msg.transport。如此，不论是简单的PL/SQL、Form或并发程序产生的短信内容，都可以作为一个整体进行日志记录。模块名可以自行定义，该定义需要有意义，并能和其他程序明确区分。该特性由配置文件 FND：调试日志模块 控制。 不需要修改代码，诊断时可以根据需要随时启用或关闭调试日志，由配置文件 FND：启用调试日志 控制。 调用示例 先在程序中创建过程，如： PROCEDURE trace(x_level IN NUMBER, x_message IN VARCHAR2) IS BEGIN IF (x_level &#62;= fnd_log.g_current_runtime_level) THEN IF (fnd_log.test(x_level, [...]]]></description>
			<content:encoded><![CDATA[<p>目前，EBS系统中存在多种日志记录方式，有用于PL/SQL的，有用于Java的，有OAF等开发框架自带的，也有Forms Server之类服务器专用的诊断方式。通常来讲，所有二次开发，为了统一规范和便于管理，应当将将客户化系统中日志记录和Oracle EBS中的日志记录进行整合，用统一的方式进行日志记录和诊断。</p>
<h4>Oracle EBS调试日志级别</h4>
<p>系统中将调试日志级别分为6个级别，分别是：</p>
<table>
<tbody>
<tr>
<th>Type</th>
<th>Level</th>
<th>Description</th>
</tr>
<tr>
<td>UNEXPECTED</td>
<td>6</td>
<td>未知异常</td>
</tr>
<tr>
<td>ERROR</td>
<td>5</td>
<td>错误</td>
</tr>
<tr>
<td>EXCEPTION</td>
<td>4</td>
<td>异常</td>
</tr>
<tr>
<td>EVENT</td>
<td>3</td>
<td>事件</td>
</tr>
<tr>
<td>PROCEDURE</td>
<td>2</td>
<td>过程</td>
</tr>
<tr>
<td>STATEMENT</td>
<td>1</td>
<td>语句，该级别最低，记录的日志信息也最详细。</td>
</tr>
</tbody>
</table>
<p>该级别通过配置文件 <strong>FND：调试日志级别</strong> 控制。</p>
<h4>调试日志模块</h4>
<p>日志必须指定当前所执行的程序，也就是所谓的模块。模块用于区分不用程序产生的日志，比如我的一套用于将EBS事件通过手机短消息发送出去的整套程序统一定义成日志模块：oracle.apps.cux.msg.transport。如此，不论是简单的PL/SQL、Form或并发程序产生的短信内容，都可以作为一个整体进行日志记录。模块名可以自行定义，该定义需要有意义，并能和其他程序明确区分。该特性由配置文件 <strong>FND：调试日志模块</strong> 控制。</p>
<p>不需要修改代码，诊断时可以根据需要随时启用或关闭调试日志，由配置文件 <strong>FND：启用调试日志</strong> 控制。</p>
<h4>调用示例</h4>
<p>先在程序中创建过程，如：</p>
<pre class="brush:sql">
PROCEDURE trace(x_level   IN NUMBER,
                x_message IN VARCHAR2) IS
BEGIN
  IF (x_level &gt;= fnd_log.g_current_runtime_level) THEN
    IF (fnd_log.test(x_level, 'oracle.apps.cux.msg.transport')) THEN
      fnd_log.STRING(log_level =&gt; x_level,
                     module    =&gt; 'oracle.apps.cux.msg.transport',
                     message   =&gt; x_message);
    END IF;
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    NULL;
END trace;</pre>
<p>然后用以下方式调用：</p>
<pre>trace(fnd_log.level_procedure, 'Enter get_num');</pre>
<h4>日志查看</h4>
<pre class="brush:sql">
SELECT *
  FROM fnd_log_messages f
 WHERE f.user_id = 1113
   AND f.log_sequence &gt; 492519740
 ORDER BY f.log_sequence;</pre>
<p>对于普通的二次开发（一些较大的平台可能需要有自己的诊断方式），建议使用通过的方式记录日志，否则，如果各行其是，或者随手就自己设计一套日志记录方式的，当开发数量到达一定规模时，会让管理工作变得复杂。</p>
<p>题外：<br />
这是早期时给团队中二次开发制订的相关规范的一部分，记在Confluence上。近日考虑撤出该平台，在角落里翻出来的一篇。另外，知识库的建设真是一项即简单又麻烦的工作……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orafans.net/2010/01/ebs-log.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
