<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-25740336</atom:id><lastBuildDate>Wed, 27 Jan 2010 21:52:39 +0000</lastBuildDate><title>The PeopleSoft DBA Blog</title><description>This blog contains things about PeopleSoft that DBAs might find interesting.&lt;br&gt;Or then again they might not!&lt;br&gt;Non-PeopleSoft Oracle stuff is at &lt;a href="http://blog.go-faster.co.uk"&gt;blog.go-faster.co.uk&lt;/a&gt;.</description><link>http://blog.psftdba.com/</link><managingEditor>info@go-faster.co.uk (David Kurtz)</managingEditor><generator>Blogger</generator><openSearch:totalResults>76</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ThePeoplesoftDbaBlog" /><feedburner:info uri="thepeoplesoftdbablog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><feedburner:emailServiceId>ThePeoplesoftDbaBlog</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-5188327023441275916</guid><pubDate>Wed, 20 Jan 2010 22:57:00 +0000</pubDate><atom:updated>2010-01-24T22:28:56.477Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">Batch Timings</category><category domain="http://www.blogger.com/atom/ns#">XML Reporting</category><title>Performance Metrics and XML Reporting in PeopleSoft</title><description>I am working with a PeopleSoft system that makes extensive use of XML Publisher reporting.&amp;nbsp; Generally these reports are based on SQL queries that are defined in the PeopleSoft PS/Query utility.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
These queries are run by an Application Engine program PSXPQRYRPT that runs the SQL query and produces the report in a single process.&amp;nbsp; This is a generic application engine program that runs any XML report.&amp;nbsp; Line 45 (in PeopleTools 8.49) of step &lt;i&gt;MAIN.ExecRPT&lt;/i&gt; executes the report with the &lt;a href="http://download.oracle.com/docs/cd/E13292_01/pt849pbr0/eng/psbooks/tpcr/htm/tpcr44.htm#g037ee99c9453fb39_ef90c_10c791ddc07__8bc" target="_blank"&gt;ProcessReport&lt;/a&gt; PeopleCode command.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: x-small;"&gt;&amp;amp;oRptDefn.ProcessReport(&amp;amp;TemplateId, &amp;amp;LanguageCd, &amp;amp;AsOfDate, &amp;amp;oRptDefn.GetOutDestFormatString(&amp;amp;OutDestFormat));&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Batch Timings&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
Analysis of the Application Engine batch timings indicate that nearly all the time in this Application Engine program is spent in PeopleCode, and that this not SQL execution time.&amp;nbsp; This is misleading.&amp;nbsp; The ProcessReport command is PeopleCode, but behind the scenes it also issues the SQL in the report data source.&amp;nbsp; Not all the time is SQL, but the Application Engine Batch Timings does not count any of this as SQL because it is not in the PeopleCode SQL Class.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
Let’s look at an example Batch Timings report (I have edited it down, removing zero and insignificant timings).&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: xx-small;"&gt;PeopleSoft Application Engine Timings
                                 (All timings in seconds)

                               C o m p i l e    E x e c u t e    F e t c h        Total           
SQL Statement                  Count   Time     Count   Time     Count   Time     Time    
------------------------------ ------- -------- ------- -------- ------- -------- --------
PeopleCode
Record.SelectByKey PSDBFIELD                          8      0.1       8      0.0      0.1
SELECT PSPRCSRQST                                     2      0.1       2      0.0      0.1
SELECT PSXPTMPLDEFN                                   3      0.1       3      0.0      0.1
                                                                                  --------
                                                                                       0.3
AE Program: PSXPQRYRPT
MAIN.ExecRpt.H                       1      0.0       1      0.0       1      0.0      0.0
                                                                                  --------
                                                                                       0.0
------------------------------------------------------------------------------------------
                               Call    Non-SQL  SQL      Total   
PeopleCode                     Count   Time     Time     Time    
------------------------------ ------- -------- -------- --------
AE Program: PSXPQRYRPT
MAIN.ExecRpt                         1    643.2      0.3    643.5
                                       -------- -------- --------
                                          643.2      0.3    643.5
------------------------------------------------------------------------------------------
                                                        E x e c u t e   
PEOPLECODE Builtin/Method                               Count   Time    
------------------------------------------------------- ------- --------
Boolean(Type 5) BuiltIns                                     90      0.1
DateTime(Type 11) BuiltIns                                    1      0.1
SQL(Type 524290) Methods                                     19      0.1
SQL(Type 524290) BuiltIns                                     9      0.1
Record(Type 524291) Methods                                1104      0.1
Session(Type 524303) Methods                                207    633.2
JavaObject(Type 524315) BuiltIns                              6      2.2
PostReport(Type 524324) Methods                               2      0.7
------------------------------------------------------------------------------------------
Total run time                :      644.0
Total time in application SQL :        0.3   Percent time in application SQL :        0.0%
Total time in PeopleCode      :      643.2   Percent time in PeopleCode      :       99.9%
------------------------------------------------------------------------------------------&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;The total execution time of is 644 seconds.&lt;/li&gt;
&lt;li&gt;643.2s are reported as being in PeopleCode, and as coming from the MAIN.ExecRpt step. &lt;/li&gt;
&lt;li&gt;Only 0.3s of that is SQL time, and that comes from PeopleCode functions in the &lt;a href="http://www.oracle.com/pls/psft/to_URL?remark=ranked&amp;amp;urlname=http:%2F%2Fdownload.oracle.com%2Fdocs%2Fcd%2FE12341_01%2Fcrm9pbr0_run2%2Feng%2Fpsbooks%2F..%2F..%2F..%2F..%2FE13292_01%2Fpt849pbr0%2Feng%2Fpsbooks%2Ftpcr%2Fbook.htm?File=tpcr%2Fhtm%2Ftpcr39.htm%23d0e141851" target="_blank"&gt;SQL Class&lt;/a&gt;&amp;nbsp; (&lt;a href="http://download.oracle.com/docs/cd/E13292_01/pt849pbr0/eng/psbooks/tpcl/htm/tpcl02.htm#g037ee99c9453fb39_ef90c_10c791ddc07__3dfe" target="_blank"&gt;CreateRecord&lt;/a&gt; , &lt;a href="http://download.oracle.com/docs/cd/E13292_01/pt849pbr0/eng/psbooks/tpcl/htm/tpcl02.htm#g037ee99c9453fb39_ef90c_10c791ddc07__3df9" target="_blank"&gt;CreateSQL&lt;/a&gt; etc.) &lt;/li&gt;
&lt;li&gt;The ProcessReport method does not appear in the PeopleCode SQL analysis section of the report, because it is not classed as SQL.&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Identifying the Report ID and Report Source&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
So, the next question is how can I find out which report this process is running.&amp;nbsp; Different instances of this report may be running different queries.&lt;br /&gt;
&lt;br /&gt;
You can get the list files generated by a process from the Content Management PeopleTools table PS_CDM_FILE_LIST.&amp;nbsp; Application Engine processes usually produce various log files (with extensions .aet, .trc and .log), the name of the other file is the same as the name of the report followed by an extension that will vary depending on format.&lt;br /&gt;
&lt;br /&gt;
You can look at the report definition on-line under Reporting Tools -&amp;gt; XML Publisher -&amp;gt; Report Definition, and that will show you the Data Source ID&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.go-faster.co.uk/images/psxprptdefn.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="2" height="211" src="http://www.go-faster.co.uk/images/psxprptdefn.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
The Data Source is defined in a component accessible from the previous entry in the same menu.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.go-faster.co.uk/images/psxpdatsrc.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="2" height="243" src="http://www.go-faster.co.uk/images/psxpdatsrc.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Analysing Execution Times&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
I have written this query to aggregate execution time for PSXPQRYRPT by output file name.&amp;nbsp; &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;PSPRCSRQST is the process request table, from which I get the run time of the process.&lt;/li&gt;
&lt;li&gt;PS_CDM_FILE_LIST lists the files generated by the process which would be posted to the Report Repository. If I exclude the usual trace files, I am left with the report ID.&lt;/li&gt;
&lt;li&gt;PSXPRPTDEFN is the report definition record, from which I can get the data source ID&lt;/li&gt;
&lt;li&gt;PSXPDATSRC specifies the data source.&amp;nbsp; A data source type (DS_TYPE) of QRY indicates a PeopleSoft PS/Query.&amp;nbsp; If it is a private query, the OPRID will have a value.&lt;/li&gt;
&lt;/ul&gt;&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: x-small;"&gt;column report_defn_id heading 'Report ID'      format a12 
column ds_type        heading 'Type'           format a4 
column ds_id          heading 'Data Source ID' format a30 
column oprid          heading 'Owner'          format a10 
column processes      heading 'Prcs'           format 990 
column reprots        heading 'Reps'           format 9,990 
column secs           heading 'Total|Seconds'  format 999,990 
column median         heading 'Median|Seconds' format 999,990 
column variance       heading 'Variance'       format 9990.0
SELECT d.report_defn_id, d.ds_type, d.ds_id, d.oprid 
,      SUM(y.processes) processes
,      SUM(y.reports) reports
,      SUM(y.secs) secs
,      median(y.secs) median
,      variance(y.secs) variance
FROM (
 SELECT x.prcsinstance
 ,      x.filename
 ,      COUNT(DISTINCT x.prcsinstance) processes
 ,      COUNT(*) reports
 ,      SUM(x.secs) secs
 FROM   (
  SELECT r.prcsinstance
  ,      f.filename
  ,      86400*(r.enddttm-r.begindttm)*ratio_to_report(1) over (partition by r.prcsinstance) secs
  FROM   sysadm.psprcsrqst r
  ,      sysadm.ps_cdm_file_list f
  WHERE  r.prcsname = 'PSXPQRYRPT'
  AND    r.prcsinstance = f.prcsinstance
  AND    NOT f.cdm_file_type IN('AET','TRC','LOG')
  AND    r.begindttm &gt;= TRUNC(SYSDATE)
  ) x
 GROUP BY x.prcsinstance, x.filename
 ) y
,      sysadm.psxprptdefn d
WHERE  d.report_defn_id = SUBSTR(y.filename,1,instr(y.filename,'.')-1)
GROUP BY d.report_defn_id, d.ds_type, d.ds_id, d.oprid 
ORDER BY secs DESC
/
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
I can now see which report process has been executed run how many times, how many copies of the report have been produced, and where the processing time is being spent, and so which one I should look at first.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: xx-small;"&gt;Total   Median
Report ID    Type Data Source ID                 Owner      Prcs   Reps  Seconds  Seconds Variance
------------ ---- ------------------------------ ---------- ---- ------ -------- -------- --------
XXX_WK_LATE  QRY  XXX_WKLY_LATENESS_RPT                       20     20    2,973      148   3702.9
XXX_HRAM_CON QRY  XXX_HRPD_CNT_AMD_RPT_QRY                    92     92    2,677       27    108.4
XXX_CKOUT_RP QRY  XXX_CHECKOUT_REPORT                         47     47    2,043       41    347.7
XXX_BNK_RPT  QRY  XXX_BNK_DTLS_SCH_QRY                         1     75      141      141      0.0
…
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If you have a SQL performance problem with an XML report because the source PS/Query performs poorly, the batch timings will lead you to believe that you have a PeopleCode problem and not a SQL problem.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Beware, this may not be the case.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Most of the execution time for XML Reports sourced from PS/Queries is almost certain to be SQL execution time.&amp;nbsp; The above query will tell you which queries are consuming how much time, and so inform your tuning effort.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-5188327023441275916?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/G1WAzoFBzxQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/G1WAzoFBzxQ/performance-metrics-and-xml-reporting.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2010/01/performance-metrics-and-xml-reporting.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-4809409387370113549</guid><pubDate>Sun, 10 Jan 2010 12:50:00 +0000</pubDate><atom:updated>2010-01-10T12:57:36.775Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">COBOL</category><category domain="http://www.blogger.com/atom/ns#">Stored Statements</category><title>Automatically Identifying Stored Statements &amp; Using DBMS_STATS in PeopleSoft Cobol</title><description>It is not possible to reference a long column in a Oracle database trigger, but it is possible to reference LOBs.  From PeopleSoft v9 Applications, the long columns have become CLOBs.  Hence, it is now possible to have a database trigger fire on insert into the Stored Statement table and so automatically make certain changes to Stored Statements as they are loaded by Data Mover.  Previously, these changes could be made by a PL/SQL script, but you had to remember to run in after any Stored Statements were reloaded.  I have published a new script (&lt;a href="http://www.go-faster.co.uk/scripts.htm#gfc_stmtid_trigger.sql" target="_blank"&gt;gfc_stmtid_trigger.sql&lt;/a&gt;) on my website that creates two such database triggers.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Trigger GFC_STMTID &lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In &lt;a href="http://www.psftdba.com/" target="_blank"&gt;PeopleSoft for the Oracle DBA&lt;/a&gt; (listing 11-23, page 280), I proposed a PL/SQL procedure to add identifying comments to stored statements (see blog entry: Identifying Application Engine Source Code), so that the statements can be identified in traces or Oracle Enterprise Manager.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
Trigger GFC_STMTSTATS&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
PeopleSoft Cobol programs do not use the PeopleSoft DDL models that Application Engine users when it processes the %UPDATESTATS macro.  In &lt;a href="http://blog.psftdba.com/2009/11/controlling-how-peoplesoft-cobol.html" target="_blank"&gt;another blog posting&lt;/a&gt;, I showed how to change the stored statements to call the &lt;a href="http://www.go-faster.co.uk/scripts.htm#wrapper848meta.sql" target="_blank"&gt;wrapper package&lt;/a&gt;, so that the program uses the Oracle supplied &lt;i&gt;dbms_stats&lt;/i&gt; procedure instead of the depreciated &lt;i&gt;ANALYZE&lt;/i&gt; command.  This trigger automatically replaces the %UPDATESTATS macro in the stored statement with a call to the wrapper package.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-4809409387370113549?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/LmGpzj_-XSw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/LmGpzj_-XSw/automatically-identify-stored.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2010/01/automatically-identify-stored.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-2366255657166583921</guid><pubDate>Thu, 17 Dec 2009 20:24:00 +0000</pubDate><atom:updated>2009-12-26T17:40:39.857Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">Hints</category><title>Hinting Sub-Queries on Oracle</title><description>This posting is a purely Oracle RDBMS discussion about how to correctly apply hints to sub-queries.  However, it is particularly relevant to PeopleSoft, which it makes extensive use of correlated sub-queries.  The point of this story is not the particular hints that I applied, but where I placed the hints, and how I scoped them to the sub-queries.&lt;br /&gt;
&lt;br /&gt;
The following SQL extract is from the delivered Global Payroll GPGB_EDI process (although I have already made some minor changes, and PS_GP_RSLT_PIN is partitioned).  Notice that each sub-query joins two tables together.  PS_GP_RSLT_PIN is second largest of Global Payroll result tables.  PS_GP_PIN is a look-up table, and the criterion on PIN_CODE will only return a single row.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;UPDATE Table(GPGB_EDIE_TMP) X
  SET X.GPGB_WK53_IND = ( 
 SELECT %TrimSubstr(%Sql(FUNCLIB_HR_CHAR,A.CALC_RSLT_VAL),1,2) 
  &lt;b&gt;FROM PS_GP_RSLT_PIN A 
  ,PS_GP_PIN B&lt;/b&gt; 
 WHERE A.EMPLID = %Table(GPGB_EDIE_TMP).EMPLID 
...&lt;/pre&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;AND A.PIN_NUM = B.PIN_NUM 
   AND B.&lt;b&gt;PIN_CODE = 'TAX VR PERIOD GBR' 
&lt;/b&gt;   AND A.SLICE_BGN_DT = ( 
 SELECT MAX(D.SLICE_BGN_DT) 
  FROM PS_GP_RSLT_PIN D 
 WHERE D.EMPLID = %Table(GPGB_EDIE_TMP).EMPLID 
...
   AND D.INSTANCE = A.INSTANCE 
   AND D.PIN_NUM = B.PIN_NUM) 
...
   )
 WHERE EXISTS ( 
...
   )
AND PROCESS_INSTANCE = %Bind(PROCESS_INSTANCE)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
This is part of the initial SQL execution plan.  The problem is that the sub-query starts by scanning through the PS_GP_RSLT_PIN table, 4 times because there are three correlated sub-queries, and only at the very end does it look up the PIN_CODE by the PIN_NUM.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 66%;"&gt;---------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                     | Name              | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| 
---------------------------------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT                              |                   |     1 |    65 |   113M (93)| 39:44:51 |       |     
|   1 |  UPDATE                                       | PS_GPGB_EDIE_TMP4 |       |       |            |          |       |     
|*  2 |   FILTER                                      |                   |       |       |            |          |       |     
|*  3 |    TABLE ACCESS FULL                          | PS_GPGB_EDIE_TMP4 |   673K|    41M|  9967   (6)| 00:00:13 |      
|   4 |    &lt;b&gt;NESTED LOOPS&lt;/b&gt;                               |                   |     1 |   108 |     4   (0)| 00:00:01 |       |     
|   5 |     PARTITION RANGE SINGLE                    |                   |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|   6 |      PARTITION LIST SINGLE                    |                   |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|*  7 |       INDEX RANGE SCAN                        | PS_GP_RSLT_PIN    |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|   8 |        SORT AGGREGATE                         |                   |     1 |    72 |            |          |       |     
|   9 |         PARTITION RANGE SINGLE                |                   |     1 |    72 |     3   (0)| 00:00:01 |   KEY | 
|  10 |          PARTITION LIST SINGLE                |                   |     1 |    72 |     3   (0)| 00:00:01 |   KEY | 
|* 11 |           INDEX RANGE SCAN                    | PS_GP_RSLT_PIN    |     1 |    72 |     3   (0)| 00:00:01 |   KEY | 
|  12 |            SORT AGGREGATE                     |                   |     1 |    83 |            |          |       |     
|  13 |             PARTITION RANGE SINGLE            |                   |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|  14 |              PARTITION LIST SINGLE            |                   |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|  15 |               FIRST ROW                       |                   |     1 |    83 |     3   (0)| 00:00:01 |       |     
|* 16 |                INDEX RANGE SCAN (MIN/MAX)     | PS_GP_RSLT_PIN    |     1 |    83 |     3   (0)| 00:00:01 | 
|  17 |                 SORT AGGREGATE                |                   |     1 |    83 |            |          |       |     
|  18 |                  PARTITION RANGE SINGLE       |                   |     1 |    83 |   158  (99)| 00:00:01 |   KEY | 
|  19 |                   PARTITION LIST SINGLE       |                   |     1 |    83 |   158  (99)| 00:00:01 |   KEY | 
|  20 |                    FIRST ROW                  |                   |     1 |    83 |   158  (99)| 00:00:01 |       |     
|* 21 |                     INDEX RANGE SCAN (MIN/MAX)| PS_GP_RSLT_PIN    |     1 |    83 |   158  (99)| 00:00:01 |   KEY |
|* 22 |     &lt;b&gt;INDEX RANGE SCAN&lt;/b&gt;                          | &lt;b&gt;PSAGP_PIN&lt;/b&gt;         |     1 |    25 |     1   (0)| 00:00:01 |       |     
...
---------------------------------------------------------------------------------------------------------------------------&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
It would be much better if we started with the PS_GP_PIN table, looked up the PIN_NUM with the PIN_CODE (there is a suitable index on this column) and used the PIN_NUM value as a part of the lookup on PS_GP_RSLT_PIN (again PIN_CODE is in the unique index on that table).  &lt;br /&gt;
&lt;br /&gt;
It is tempting to add LEADING hints to the sub-queries, but such a hint does not work because the hint is not scoped to the sub-query and is considered to be invalid because the entire query cannot start at this point.  &lt;br /&gt;
&lt;br /&gt;
The only supported place in the query to add a LEADING hint would be the first query, in this case after the UPDATE keyword.  &lt;br /&gt;
&lt;br /&gt;
In this case, I have named the query blocks in the sub-queries with the QB_NAME hint.  It is valid to put this hint into the sub-query.  Then I added LEADING hints for each sub-query after the UPDATE keyword, but I specified their scope using the name of the sub-query specified in the QB_NAME hint.  Each sub-query must now start with the PS_GP_PIN table.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;UPDATE &lt;b&gt;/*+LEADING(@SUB1 B@SUB1) LEADING(@SUB2 B@SUB2)*/&lt;/b&gt; %Table(GPGB_EDIE_TMP) X
  SET X.GPGB_WK53_IND = ( 
 SELECT &lt;b&gt;/*+QB_NAME(SUB1)*/&lt;/b&gt; %TrimSubstr(%Sql(FUNCLIB_HR_CHAR,A.CALC_RSLT_VAL),1,2) 
  FROM PS_GP_RSLT_PIN A 
  ,PS_GP_PIN B 
 WHERE A.EMPLID = %Table(GPGB_EDIE_TMP).EMPLID 
...
   AND A.PIN_NUM = B.PIN_NUM 
   AND B.PIN_CODE = 'TAX VR PERIOD GBR' 
   AND A.SLICE_BGN_DT = ( 
 SELECT MAX(D.SLICE_BGN_DT) 
  FROM PS_GP_RSLT_PIN D 
 WHERE D.EMPLID = %Table(GPGB_EDIE_TMP).EMPLID 
...
   AND D.INSTANCE = A.INSTANCE 
   AND D.PIN_NUM = B.PIN_NUM) 
...
   )
 WHERE EXISTS ( 
 SELECT &lt;b&gt;/*+QB_NAME(SUB2)*/&lt;/b&gt; 'X' 
  FROM PS_GP_RSLT_PIN A1 
  ,PS_GP_PIN B1 
 WHERE A1.EMPLID = %Table(GPGB_EDIE_TMP).EMPLID 
...
   AND A1.PIN_NUM = B1.PIN_NUM 
   AND B1.PIN_CODE = 'TAX VR PERIOD GBR' 
...
   )
AND PROCESS_INSTANCE = %Bind(PROCESS_INSTANCE)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
This is the new execution plan.  The sub-query starts with an access of index PSAGP_PIN (which leads on PIN_CODE) on PS_GP_PIN, and then does the lookups on PS_GP_RSLT_PIN.  The cost is the same, but the execution time was considerably reduced.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 66%;"&gt;----------------------------------------------------------------------------------------------------
| Id  | Operation                                     | Name              | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| 
----------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT                              |                   |     1 |    65 |   113M (93)| 39:44:51 |       |     
|   1 |  UPDATE                                       | PS_GPGB_EDIE_TMP4 |       |       |            |          |       |     
|*  2 |   FILTER                                      |                   |       |       |            |          |       |     
|*  3 |    TABLE ACCESS FULL                          | PS_GPGB_EDIE_TMP4 |   673K|    41M|  9967   (6)| 00:00:13 |       |
|   4 |    &lt;b&gt;NESTED LOOPS&lt;/b&gt;                               |                   |     1 |   108 |     4   (0)| 00:00:01 |       |     
|*  5 |     &lt;b&gt;INDEX RANGE SCAN&lt;/b&gt;                          | &lt;b&gt;PSAGP_PIN&lt;/b&gt;         |     1 |    25 |     2   (0)| 00:00:01 |       |     
|   6 |     PARTITION RANGE SINGLE                    |                   |     1 |    83 |     2   (0)| 00:00:01 |   KEY | 
|   7 |      PARTITION LIST SINGLE                    |                   |     1 |    83 |     2   (0)| 00:00:01 |   KEY | 
|*  8 |       INDEX RANGE SCAN                        | PS_GP_RSLT_PIN    |     1 |    83 |     2   (0)| 00:00:01 |   KEY | 
|   9 |        SORT AGGREGATE                         |                   |     1 |    72 |            |          |       |     
|  10 |         PARTITION RANGE SINGLE                |                   |     1 |    72 |     3   (0)| 00:00:01 |   KEY | 
|  11 |          PARTITION LIST SINGLE                |                   |     1 |    72 |     3   (0)| 00:00:01 |   KEY | 
|* 12 |           INDEX RANGE SCAN                    | PS_GP_RSLT_PIN    |     1 |    72 |     3   (0)| 00:00:01 |   KEY | 
|  13 |            SORT AGGREGATE                     |                   |     1 |    83 |            |          |       |     
|  14 |             PARTITION RANGE SINGLE            |                   |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|  15 |              PARTITION LIST SINGLE            |                   |     1 |    83 |     3   (0)| 00:00:01 |   KEY | 
|  16 |               FIRST ROW                       |                   |     1 |    83 |     3   (0)| 00:00:01 |       |     
|* 17 |                INDEX RANGE SCAN (MIN/MAX)     | PS_GP_RSLT_PIN    |     1 |    83 |     3   (0)| 00:00:01 |       |
|  18 |                 SORT AGGREGATE                |                   |     1 |    83 |            |          |       |     
|  19 |                  PARTITION RANGE SINGLE       |                   |     1 |    83 |   158  (99)| 00:00:01 |   KEY | 
|  20 |                   PARTITION LIST SINGLE       |                   |     1 |    83 |   158  (99)| 00:00:01 |   KEY | 
|  21 |                    FIRST ROW                  |                   |     1 |    83 |   158  (99)| 00:00:01 |       |     
|* 22 |                     INDEX RANGE SCAN (MIN/MAX)| PS_GP_RSLT_PIN    |     1 |    83 |   158  (99)| 00:00:01 |   KEY |
|  23 |   TABLE ACCESS BY LOCAL INDEX ROWID           | PS_GP_RSLT_PIN    |     1 |    86 |     3   (0)| 00:00:01 |       |
...
---------------------------------------------------------------------------------------------------------------------------&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-2366255657166583921?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/ftiFib7mYYA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/ftiFib7mYYA/hinting-sub-queries-on-oracle.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/12/hinting-sub-queries-on-oracle.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-400004847550273152</guid><pubDate>Wed, 25 Nov 2009 08:23:00 +0000</pubDate><atom:updated>2010-01-10T12:41:42.378Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">COBOL</category><category domain="http://www.blogger.com/atom/ns#">Stored Statements</category><title>Controlling How PeopleSoft Cobol Collects Statistics</title><description>In previous postings, I have proposed &lt;a href="http://blog.psftdba.com/2008/06/oracle-optimizer-statistics-and.html"&gt;locking statistics&lt;/a&gt; on temporary working storage tables and &lt;a href="http://blog.psftdba.com/2009/06/controlling-how-updatestats-collects.html"&gt;changing the DDL model for %UpdateStats&lt;/a&gt; to call my own PL/SQL Package.&amp;nbsp; That works for Application Engine programs, but PeopleSoft COBOL can also update object statistics, and they use a different mechanism.&lt;br /&gt;
&lt;br /&gt;
In the case of the Global Payroll calculation engine, &lt;i&gt;GPPDPRUN&lt;/i&gt;, the run control component has a secondary page with a check box to enable statistics collection during the process.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.go-faster.co.uk/images/gppdpruncntl.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="2" height="100" src="http://www.go-faster.co.uk/images/gppdpruncntl.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
However, to get streamed processing in Payroll (where the population of employees is broken into ranges of employee IDs that are each processed by a different concurrent process) to work effectively I change the working storage tables to be Global Temporary Tables, and then because the different physical instances would still share statistics (&lt;a href="http://blog.go-faster.co.uk/2009/10/global-temporary-tables-shared.html"&gt;Global Temporary Tables Share Statistics Across Sessions&lt;/a&gt;) I delete and lock the statistics on these tables.&lt;br /&gt;
&lt;br /&gt;
If the payroll calculation is run with the Update Statistics option it generates the following error. &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;Application Program Failed
 Action Type     : SQL UPDATE
 In Pgm Section  : SQLRT: EXECUTE-STMT                                 
 With Return Code: 38029 
 Error Message   : ORA-38029: object statistics are locked
 Stored Stmt     : GPPSERVC_U_STATS  
 SQL Statement   : ANALYZE TABLE PS_GP_PYE_STAT_WRK ESTIMATE STATISTICS&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
COBOL issued an ANALYZE command, and did not use the DDL model defined in the table PSDDLMODEL.&amp;nbsp; However, the command came from a stored statement, in this case GPPSERVC_U_STATS.&amp;nbsp; The stored statement is defined as follows in the gppservc.dms.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;STORE GPPSERVC_U_STATS
%UPDATESTATS(PS_GP_PYE_STAT_WRK)
;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
So, the expansion of %UPDATESTATS in the stored statement to the ANALYZE command is hard coded somewhere in the delivered executable code.&amp;nbsp; I would not suggest attempting to change that.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
However, it is perfectly possible to change the stored statement to call the wrapper package (&lt;a href="http://www.go-faster.co.uk/scripts/wrapper848meta.sql" target="_blank"&gt;www.go-faster.co.uk/scripts/wrapper848meta.sql&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;STORE GPPSERVC_U_STATS
BEGIN wrapper.ps_stats(p_ownname=&amp;gt;user, p_tabname=&amp;gt;'PS_GP_PYE_STAT_WRK'); END;; &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
In all there are 5 statements in HR 9.0 that call %UPDATESTATS that all relate to GPPDPRUN.&amp;nbsp; I generated a data mover script to replace them with calls to my replacement package using the following SQL.script.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: #eeeeee; border: 0px solid rgb(0, 0, 0); overflow: auto; padding-left: 4px; padding-right: 4px; width: 100%;"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;set head off feedback off long 5000
spool updatestats_after.dms
select 'STORE '||pgm_name||'_'||stmt_type||'_'||stmt_name
||CHR(10)
||'BEGIN wrapper.ps_stats(p_ownname=&amp;gt;user,p_tabname=&amp;gt;'''
||substr(stmt_text
 , INSTR(stmt_text,'(')+1
 , INSTR(stmt_text,')')-INSTR(stmt_text,'(')-1
 )
||'''); END;;'
from ps_sqlstmt_tbl
where stmt_text like '%UPDATESTATS(%'
/
spool off&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
I have only tested this against HR9.0. Note that long columns such as PS_SQLSTMT_TBL.STMT_TEXT only become CLOBs when the application version reaches 9.0. &amp;nbsp; You cannot use the LIKE operation on the long column.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-400004847550273152?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/k_jAQLOUG6I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/k_jAQLOUG6I/controlling-how-peoplesoft-cobol.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/11/controlling-how-peoplesoft-cobol.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-2021058070571426795</guid><pubDate>Wed, 28 Oct 2009 08:19:00 +0000</pubDate><atom:updated>2009-10-28T08:19:28.430Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">Database Links</category><title>Database Links and PeopleSoft</title><description>I have seen Oracle database links used in conjuction with PeopleSoft at a number of customer sites over the years.  I think some scenarios are examples where it is reasonable to use a database link, some are not.&lt;br /&gt;
In Oracle RDBMS, a database link (see also the &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e10595/ds_concepts002.htm#i1007709"&gt;Oracle Concepts Manual&lt;/a&gt;) specifies how a database server can create a session on another database in order to perform a remote operation. The remote database may be another Oracle database, or another type of database.  The remote operation may be a query, or it may modify remote data (DML operation), in which case a two-phase commit mechanism ensures transaction integrity across the databases.&lt;br /&gt;
&lt;br /&gt;
PeopleSoft does not use database links between databases because they are a database platform specific technology. Instead, the PeopleSoft methodology is to replicate data between databases with an application message. This works well with small data sets, and with larger data sets that change slowly. However, there are scenarios with very large data volumes where Application Messaging will struggle to keep up, and Oracle RDMBS specific replication technologies are an appropriate alternative. &lt;br /&gt;
&lt;br /&gt;
Data can be replicated between databases with Materialised Views (formerly known as Snapshots).  This is a SQL based technology.  Materialised Views Logs on the source database track changes in the source table.  An incremental or full refresh process is run on the target, usually as a scheduled job. &lt;br /&gt;
&lt;br /&gt;
Oracle introduced an alternative replication technology in Oracle 9i called ‘Streams’. This uses supplementary redo logging on the source database which can then be applied to the target. Additional database server processes transmit, receive and apply this redo stream.  This technology is aimed a large volume replication for data warehouses.  I know of one site where several hundred database tables are replicated from PeopleSoft HR to a data warehouse.&lt;br /&gt;
&lt;br /&gt;
I think the clearest way is to explain the good and bad use of links is by example.&lt;br /&gt;
&lt;br /&gt;
At two different sites with HR and Finance, I have seen similar examples of both good and bad use of database links (one was on PeopleTools 7.0, before Application Messaging was available).&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;GL data needs to be sent from Payroll in the HR database to GL in the Financials database.  The PeopleSoft delivered mechanism was to use generate and reload an interface file.  This customer changed replaced the interface table in HR with a view that referenced a table with the same name and structure on the Financial system via a link.  The payroll GL extract process now inserted directly into the table on Financials.  I think this is a perfectly reasonable use of a database link.  It was simple.  It performed better than the interface file, and would certainly have been faster than application messaging.&amp;nbsp; &lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;However, the same customer also used the employee expenses module in Financials. This required employee personal data. So they made the PS_PERSONAL_DATA table in Financials a view of the corresponding table in HR. The result was that every time somebody opened the expenses component in Financials, the application server process referenced the database link to HR. There is a limit on the maximum number of database links that a session can concurrently open (OPEN_LINKS) and that the whole database instance can concurrently open (OPEN_LINKS_PER_INSTANCE). They both default is 4, which gives an indication of how Oracle expect you to use this feature. This system ran out of database links.  No Oracle errors were generated, instead sessions wait to be allowed to make the connection to the remote database. There are specific database link wait events that report the amount of time lost.&amp;nbsp; Eventually you reach the point where Tuxedo services timeout and then users receive errors.  I think this is an example of the wrong way to use a database link.  Instead I think that the data should have been replicated from HR to Financials.  In a modern PeopleSoft system this should be done with an application message (on the 7.0 system a Materialised View could have been used).&amp;nbsp; &lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Not only were database links used to provide data to components, but the same views, that referenced remote objects, were used in queries and reports resulting in complex distributed queries.  When multiple remote objects are referenced in a single SQL, I have seen Oracle decide to copy the whole of one or more of these objects to the local temporary tablespace.  This does not result in good performance.  Remember also, that even query only operations via a database link create a transaction on the remains until a commit or rollback is issued. &lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;I worked on another site where Materialised Views were used to incrementally replicate data from CRM and HR to EPM databases. Processes in the EPM database then referenced the Materialised Views. In this system, there was never any question of EPM processes referencing objects via the links.  The data volumes were such that Application Messaging would never have coped.  In this case only the Materialised View refresh process references the database links, and so the DBA can manage the usage of links.  This is a system where (after upgrade to Oracle 10g) Streams could also have been used to replicate the data.&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
My view is that database links should not be used to directly support functionality in either on-line components or reporting. When this is done in reports and queries it presents the problem of tuning distributed queries, and having to decide whether local or remote database should drive the query. Instead data should be replicated to the local database, preferably by PeopleSoft messaging, but if necessary by Oracle replication. However, I think that it can be reasonable to use a database link in an occasional batch process that moves data between systems.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-2021058070571426795?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/jYNw-Yyh_IU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/jYNw-Yyh_IU/database-links-and-peoplesoft.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">7</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/10/database-links-and-peoplesoft.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-310734979297341651</guid><pubDate>Sun, 11 Oct 2009 16:55:00 +0000</pubDate><atom:updated>2009-10-11T17:55:10.406+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Batch Timings</category><title>Aggregating &amp; Purging Batch Timings</title><description>Application Engine can collect timing information for the programs being execution.  These 'batch timings' can be written to log file and/or tables in the database.  I always recommend that this is enabled in all environments.  The runtime overhead is very low, and this data is extremely valuable to determine the performance of a system over a period of time, and to identify the pieces of SQL or PeopleCode code that account for the most time.  The timing data collected for individual processes can be viewed directly within the Process Monitor component.&lt;br /&gt;
&lt;br /&gt;
The Process Scheduler purge process does not delete batch timings, so this data remains in the database indefinitely, although it can no longer be accessed via the Process Monitor.  Over time, on a busy system, a large volume of data can accumulate. In some ways this is a good thing.  There are good reasons to purge the Process Scheduler as aggressively as the business will permit.&amp;nbsp; The batch timings can still be analysed by direct SQL query. However, the sheer volume of data is likely to result in queries that can take quite a while to execute.  After a while, you are less likely to be interested in the performance of individual processes, but are more likely to want to aggregate the data.  So, it makes sense to hold the data at least partly aggregated.  &lt;br /&gt;
&lt;br /&gt;
I have produced a very simple Application Engine program (&lt;a href="http://www.go-faster.co.uk/scripts.htm#gfc_timings_arch"&gt;GFC_TIM_ARCH&lt;/a&gt;) to address this problem.  This program is available for &lt;a href="http://www.go-faster.co.uk/scripts.htm#gfc_timings_arch"&gt;download from the Go-Faster website&lt;/a&gt; as a PeopleTools Application Designer Project.  Please note that this process has been written using Oracle RDBMS specific SQL syntax.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Application Engine stores batch timing data in three table &lt;i&gt;PS_BAT_TIMINGS_LOG&lt;/i&gt;, &lt;i&gt;PS_BAT_TIMINGS_FN&lt;/i&gt; and &lt;i&gt;PS_BAT_TIMINGS_DTL&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;I have created three new tables &lt;i&gt;PS_GFC_TIMINGS_LOG&lt;/i&gt;, &lt;i&gt;PS_GFC_TIMINGS_FN&lt;/i&gt; and &lt;i&gt;PS_GFC_TIMINGS_DTL&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;GFC_TIM_ARCH&lt;/i&gt; aggregates the data in each of these tables by the day on which the process begin, by the process name, and (where applicable) by the 'detail_id' column.  The aggregated data is put into the &lt;i&gt;GFC_TIMINGS%&lt;/i&gt; tables, the original data is removed from the &lt;i&gt;BAT_TIMINGS%&lt;/i&gt; tables.&lt;/li&gt;
&lt;li&gt;It finds the earliest three days for which timing data exists that is older than the longest Process Scheduler retention limit.  The idea is that the process should be run daily (the delivered 'Daily Purge' recurrence is suitable), but if it doesn't run for some reason it will catch up the next day.&lt;/li&gt;
&lt;li&gt;Only one instance of WMS_TIM_ARCH is permitted to run concurrently.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
On one system, where I tested this process, &lt;i&gt;BAT_TIMINGS_DTL&lt;/i&gt; was growing by over 1 million rows per day.  This became around 5000 rows per day in &lt;i&gt;GFC_TIMINGS_DTL&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
If you have been running with batch timings for a while, then when you first introduce this process you will probably have a large backlog of data to be aggregated and purged.  The easiest option is to run this process repeatedly until the data has been processed (possibly using the recurrence that causes a program to run every minute).  After the backlog has been cleared the &lt;i&gt;BAT_TIMINGS%&lt;/i&gt; tables should be rebuilt or shrunk in order to release the space left in the tables by the deleted rows.  This will help queries that scan the &lt;i&gt;BAT_TIMINGS_DTL&lt;/i&gt; record, otherwise these scans still need to include the empty rows because they are below the tables High Water Mark.&lt;br /&gt;
&lt;br /&gt;
Once the backlog has been cleared, the &lt;i&gt;GFC_TIM_ARCH&lt;/i&gt; process can run daily and, not withstanding variations in the load on the system, the rolling volume of data retained in the &lt;i&gt;BAT_TIMINGS%&lt;/i&gt; tables should be fairly constant, and it should not be necessary to rebuild them frequently.  Space freed by the daily delete should be used by new rows that are inserted into the table as AE processes run.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-310734979297341651?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/FTvkJIVehVE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/FTvkJIVehVE/aggregating-purging-batch-timings.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/10/aggregating-purging-batch-timings.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-8773421305452583790</guid><pubDate>Thu, 10 Sep 2009 18:40:00 +0000</pubDate><atom:updated>2009-09-11T14:20:00.643+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Application Engine</category><title>Identifying Application Engine Source Code</title><description>One of the recurring challenges of performance tuning PeopleSoft systems is that having identified a problem SQL statement with the aid of a database utility, such as Oracle Enterprise Manager or session trace, you often need to identify the source so that you can implement a change.&lt;br /&gt;&lt;br /&gt;Stored Outlines and SQL Profiles do not work well with PeopleSoft.  Bind variables in Application Engines often become literals before the SQL statement is submitted to the database, unless the &lt;a target="_blank" href="http://blog.psftdba.com/2009/02/performance-benefits-of-reuse-statement_27.html"&gt;ReUse Statement&lt;/a&gt; feature has been enabled, which it is not by default.&lt;br /&gt;&lt;br /&gt;I wrote about this in &lt;a target="_blank" href="http://www.psftdba.com/"&gt;PeopleSoft for the Oracle DBA&lt;/a&gt;, it contains a script called &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts/stmtid.sql"&gt;stmtid.sql&lt;/a&gt; (listing 11-23, page 280) that adds an identifying comment to each of the stored statements used by PeopleSoft COBOL programs.&lt;br /&gt;&lt;br /&gt;Now, I have produced a similar script for Application Engine programs.  The script &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#aeid.sql"&gt;aeid.sql&lt;/a&gt; adds identification comments containing the name of object.  It directly modifies the PeopleTools tables for Application Engine steps and PeopleSoft SQL objects.  These comments will be seen in database tools and traces.  So now when your database tools find a problem statement, it is easy to find the source.&lt;br /&gt;&lt;br /&gt;Below, is part of a screen shot from Oracle Enterprise Manager.  You can see the identifying comment in the SQL, which was added by this script&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.go-faster.co.uk/images/aeid.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 100%;" src="http://www.go-faster.co.uk/images/aeid.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The comment identifies the name of the Application Engine program, section, step and step type.   In this example, the SQL is from an Application Engine ID &lt;span style="font-style: italic;"&gt;GPGB_EDI_PRC&lt;/span&gt;, in section called &lt;span style="font-style: italic;"&gt;EDI_PRC&lt;/span&gt;, in a SQL type step called &lt;span style="font-style: italic;"&gt;Step01&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;For example, if you need adjust this SQL statement, perhaps add a hint to it, you don't have to spend time working out where it came from.  It is not uncommon to find many similar SQL statements in a program.  Also, where dynamic code is used to generate the SQL statement, it can be very tricky to find the exact source.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Using aeid.sql&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;u&gt;You will need to edit the script each time&lt;/u&gt;, to specify which Application Engine programs and SQL objects are to be commented.  The script is not perfect.  It does not handle some very long statements, so you cannot simply instrument the entire system in one go.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The script is designed to run in SQL*Plus.&lt;/li&gt;&lt;li&gt;It produces a report of statements that it has altered.&lt;/li&gt;&lt;li&gt;The script does not commit.  You should either &lt;span style="font-style: italic;"&gt;commit&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;rollback&lt;/span&gt; the update depending upon whether you are satisfied with the output.&lt;/li&gt;&lt;li&gt;I suggest that the script only be run in pre-production environments.  The comments will of course be migrated along with any other changes.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-8773421305452583790?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/L9jPPEVC7PA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/L9jPPEVC7PA/identifying-source-code.html</link><author>info@go-faster.co.uk (David Kurtz)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_SlmmwRbAUdk/Sql0jfseO9I/AAAAAAAAALY/SOUD2gsIR4s/s72-c/aeid.JPG" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/09/identifying-source-code.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-1358044497525697450</guid><pubDate>Tue, 28 Jul 2009 05:39:00 +0000</pubDate><atom:updated>2009-07-28T07:25:47.865+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Truncate</category><category domain="http://www.blogger.com/atom/ns#">Freelist</category><category domain="http://www.blogger.com/atom/ns#">ASSM</category><title>Automatic Segment Space -v- Freelist Management for PeopleSoft Temporary Records</title><description>&lt;style type="text/css"&gt;.nobr br { display: none }&lt;/style&gt;Earlier this year, I wrote about some research into the &lt;a target="_blank" href="http://blog.psftdba.com/2009/01/performance-implications-of-concurrent.html"&gt;effects of concurrent TRUNCATE TABLE operations in concurrent PeopleSoft Application Engine process&lt;/a&gt;.  Since then I have been prompted to look at the effect of Automatic Segment Space -v- Freelist (or Manual) Management.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/physical.htm#sthref523"&gt;ASSM&lt;/a&gt; was introduced in Oracle 9i for Locally Managed Tablespaces, and from Oracle 10g it is default option,  It was designed for high concurrency systems, and avoids some of the problems, such as contention on header blocks, that can occur with Freelist Management.  It uses tracking blocks to indicate utilisation of data blocks.  The ASSM structure is similar to a B-tree index (see Tanel Poder's presentation: &lt;a target="_blank" href="http://www.tanelpoder.com/files/Poder_Freelists_vs_ASSM.ppt"&gt;Freelists -v- ASSM in Oracle 9i&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Normally, using ASSM is preferable in multi-user OLTP systems.  The reduction in contention on the freelists should outweigh the additional I/O for the tracking blocks.&lt;br /&gt;&lt;br /&gt;However, non-shared instances of PeopleSoft Temporary Records are only used by a single Application Engine process at any one time.  Therefore, there would be no contention on freelists for these objects, and so DML operations on these objects will not derive much benefit from ASSM.  In fact, the contrary could easily be true.  The additional tracking blocks are also maintained during DML and are cleared out by local writes during a truncate operation.  Truncate operations are serialised in Oracle on the RO enqueue.  If you run multiple concurrent Application Engine programs you can get contention between the truncate operations.  The additional I/O on the ASSM tracking blocks causes the truncate to take longer and in extreme cases can aggravate truncate contention.&lt;br /&gt;&lt;br /&gt;The local write operations that occur during truncate operations cannot be deferred.  Significant truncate contention can be a symptom of disk contention.  However, switching back to Freelist Management saves the I/O to the tracking blocks, and so improves the performance of truncate.&lt;br /&gt;&lt;br /&gt;I ran a test where I truncated a table with 5000 rows.  I examined an Oracle trace with waits of the truncate.  I tested it in an ASSM tablespace, and Freelist Managed tablespace.  I tested truncating just the table on its own, and sometimes with an index.&lt;br /&gt;&lt;br /&gt;&lt;div class="nobr" style="width: 100%; overflow: auto; border: 0px solid #000000; padding-left: 4px; padding-right: 4px; background-color:#EEEEEE;font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;table border="1" cellpadding="2" cellspacing="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt;Number of Wait Events&lt;/th&gt;&lt;br /&gt;&lt;th colspan="3"&gt;&lt;p align="center"&gt;Table only, without any indexes&lt;/p&gt;&lt;/th&gt;&lt;br /&gt;&lt;th colspan="3"&gt;&lt;p align="center"&gt;With a single primary key index&lt;/p&gt;&lt;/th&gt;&lt;br /&gt;&lt;/tr&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Tablespace Type&lt;/td&gt;&lt;br /&gt;&lt;th&gt;db file sequential read&lt;/th&gt;&lt;br /&gt;&lt;th&gt;enq: RO - fast object reuse&lt;/th&gt;&lt;br /&gt;&lt;th&gt;local writes&lt;/th&gt;&lt;br /&gt;&lt;th&gt;db file sequential read&lt;/th&gt;&lt;br /&gt;&lt;th&gt;enq: RO - fast object reuse&lt;/th&gt;&lt;br /&gt;&lt;th&gt;local writes&lt;/th&gt;&lt;br /&gt;&lt;/tr&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Automatic Segment Space Management&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;8&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;1&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;4&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;16&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;2&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;9&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Freelist Management&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;3&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;1&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;1&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;6&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;2&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;p align="center"&gt;3&lt;/p&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;You can see from this table that the truncates in the ASSM tablespace required more single block reads (db_file_sequential_read) and more local writes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Recommendation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In addition to my &lt;a target="_blank" href="http://blog.psftdba.com/2009/01/performance-implications-of-concurrent.html"&gt;previous recommendation&lt;/a&gt; to move the all (non-shared instances) of temporary working storage tables, and their indexes, to tablespaces with a larger block size, I also recommend that those tablespaces should be specified with MANUAL segment space management.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-1358044497525697450?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/JI8-mAaRdB0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/JI8-mAaRdB0/automatic-segment-space-v-freelist.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/07/automatic-segment-space-v-freelist.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-5691892938693685558</guid><pubDate>Thu, 23 Jul 2009 18:41:00 +0000</pubDate><atom:updated>2009-09-22T21:36:27.226+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Recyclebin</category><title>PeopleSoft and the Oracle Recycle Bin</title><description>If you are running PeopleSoft on Oracle 10g, what do you do about the &lt;a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14231/tables.htm#i1011340"&gt;Recycle Bin&lt;/a&gt;?  It is a new feature in Oracle 10g, and it is enabled by default.  So you are using it, unless you have taken a decision to the contrary.&lt;br /&gt;&lt;br /&gt;It works just like the Windows recycle bin.  You can drop a table and then flash it back (they didn't call it UNDROP because Oracle marketing now calls everything Flashback).  So when you drop a table, Oracle marks it as dropped, and renames it with a system generated name beginning with BIN$.  You can look at the contents of the Recycle Bin through a catalogue view.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;&gt;create table t (a number);&lt;br /&gt;&gt;drop table t;&lt;br /&gt;&gt;select * from user_recyclebin&lt;br /&gt;&lt;br /&gt;OBJECT_NAME                    ORIGINAL_NAME                    OPERATION TYPE&lt;br /&gt;------------------------------ -------------------------------- --------- -------------------------&lt;br /&gt;TS_NAME                        CREATETIME          DROPTIME               DROPSCN&lt;br /&gt;------------------------------ ------------------- ------------------- ----------&lt;br /&gt;PARTITION_NAME                   CAN CAN    RELATED BASE_OBJECT PURGE_OBJECT      SPACE&lt;br /&gt;-------------------------------- --- --- ---------- ----------- ------------ ----------&lt;br /&gt;BIN$ZCLja8iAA9LgRAAOf+3h5A==$0 T                                DROP      TABLE&lt;br /&gt;PSDEFAULT                      2009-03-02:13:35:12 2009-03-02:13:35:14 9.7561E+12&lt;br /&gt;                          YES YES     776642      776642       776642          4&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If you don't want a table to go into the recycle bin when you drop it, you can code DROP TABLE ... PURGE - but PeopleSoft doesn't do this.&lt;br /&gt;&lt;br /&gt;PeopleSoft alter scripts usually drop and recreate tables.  In a production system this is often the best option, otherwise you run the risk of causing rows to migrate to other blocks when you add new columns.   In one system, I found 17000 objects in the recycle bin, occupying 1.3Gb.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;My Opinion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Personally, I would disable the recycle bin by setting the initialisation parameter &lt;a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/initparams175.htm"&gt;RECYCLEBIN = OFF&lt;/a&gt; in all PeopleSoft environments, with the possible exception of the development environment.&lt;br /&gt;&lt;br /&gt;The RECYCLEBIN parameter can also be set dynamically at session or system level.  You could perhaps turn it on prior to upgrade/data migration procedures, and then when satisfied turn it off again and manually purge the recycle bin.&lt;br /&gt;&lt;br /&gt;I think Oracle features should be used knowingly.  It doesn't matter whether you decide to use a feature or not.  It &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; important that in making that decision you have thought about how to deal with the implications, rather than be surprised later.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-5691892938693685558?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/6HqeSYbqXSU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/6HqeSYbqXSU/peoplesoft-and-oracle-recycle-bin.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/07/peoplesoft-and-oracle-recycle-bin.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-3231799605698304596</guid><pubDate>Tue, 14 Jul 2009 09:18:00 +0000</pubDate><atom:updated>2009-07-14T11:59:59.218+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Terminated Connection Timeout</category><category domain="http://www.blogger.com/atom/ns#">Dead Connect Detection</category><category domain="http://www.blogger.com/atom/ns#">SQL*Net</category><title>Oracle Terminated Connection Timeout</title><description>I have recently come across situations on two different PeopleSoft sites where ad-hoc queries continue to run on the Oracle database server long after the Application Server process, which is the Oracle session client, has terminated. Often, queries perform poorly because they are poorly coded, but that is another story.   To help guard against this situation Oracle has mechanism called &lt;a target="_blank" href="http://download.oracle.com/docs/cd/B28359_01/network.111/b28316/profile.htm#sthref694"&gt;Terminated Connection Timeout&lt;/a&gt; (also known as &lt;a target="_blank" href="http://download-west.oracle.com/docs/cd/A87860_01/doc/network.817/a76933/concepts.htm#997825"&gt;Dead Connection Detection&lt;/a&gt; (DCD) when it was introduced in Net8).&lt;br /&gt;&lt;br /&gt;Metalink Note &lt;a target="_blank" href="https://metalink3-dr.oracle.com/od/faces/secure/km/DocumentDisplay.jspx?id=615782.1&amp;amp;h=Y"&gt;615782.1&lt;/a&gt; explains the mechanism. &lt;span&gt;"DCD is initiated on the server when a connection is established. At this time SQL*Net reads the SQL*Net parameter files and sets a timer to generate an alarm.   The timer interval is set by providing a non-zero value in &lt;u&gt;minutes&lt;/u&gt; for the &lt;span style="font-style: italic;"&gt;SQLNET.EXPIRE_TIME&lt;/span&gt; parameter in the &lt;span style="font-style: italic;"&gt;sqlnet.ora&lt;/span&gt; file on the database server side. When the timer expires, SQL*Net on the server sends a 'probe' packet, essentially an empty SQL*Net packet, to the client. If the client end of the connection is still active, the probe is discarded, and the timer mechanism is reset.  If the client has terminated abnormally, the server will receive an error from the send call issued for the probe, and SQL*Net on the server will signal the operating system to release the connection's resources."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Thus, if a PeopleSoft operator initiates an ad-hoc query that runs on the &lt;span style="font-style: italic;"&gt;PSQRYSRV&lt;/span&gt; server for longer than the &lt;span style="font-style: italic;"&gt;ICQuery &lt;/span&gt;service time-out (default 1200 seconds), then Tuxedo will terminate and restart the busy server process.  However, the query will continue run on the database server until the current fetch operation returns.  In the case of a query performing a large sort or hash operation, it might be a long time before the first row is returned.  All the while, the query is continuing to consume resources on the database.&lt;br /&gt;&lt;br /&gt;PeopleTools 8.44, also introduced the ability to kill a query via the Query Monitor that had reached a maximum run time.  This is one of the functions of the PSMONITORSRV server process (see Metalink Note &lt;a target="_blank" href="https://metalink3-dr.oracle.com/od/faces/secure/km/DocumentDisplay.jspx?id=624339.1&amp;amp;h=Y"&gt;624339.1&lt;/a&gt;.   The maximum run time is specified in a permission list (see Security Administration PeopleBook &lt;a target="_blank" href="http://download.oracle.com/docs/cd/E13292_01/pt849pbr0/eng/psbooks/tsec/chapter.htm?File=tsec/htm/tsec04.htm%23d0e5379"&gt;Permission List Query Profile&lt;/a&gt;) and then the ability to kill queries that have timed out can be enabled or disabled system-wide (see PeopleSoft Query PeopleBook &lt;a target="_blank" href="http://download.oracle.com/docs/cd/E13292_01/pt849pbr0/eng/psbooks/tpsq/chapter.htm?File=tpsq/htm/tpsq09.htm%23d0e8623"&gt;Query Administration&lt;/a&gt;. It will kill the application server process that submitted the query, but for the same reasons, the query may continue to run on the database.&lt;br /&gt;&lt;br /&gt;Thus, setting Terminated Connection Timeout is not merely a good idea for a PeopleSoft system running on Oracle, it is effectively mandatory.  Otherwise. some PeopleSoft functionality simply won't work as intended.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What is an appropriate value for SQLNET.EXPIRE_TIME?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The value for this parameter is the time between successive SQL*Net probes sent by the Oracle shadow server process to the client.  Setting it is a balance between the maximum time that a query can be left to consume resources after a client process terminates, against the additional overhead of every client process sending a probe every few minutes.&lt;br /&gt;&lt;br /&gt;The SQL*Net documents often talk about additional network traffic generated by DCD.  This was a consideration in the past on client-server applications that ran across a wide area network.  However, it is rarely a consideration in relatively modern systems such as PeopleTools 8, the database connections are made by Application Server and Process Scheduler, which are usually physically close to the database server.&lt;br /&gt;&lt;br /&gt;The time-out can be set independently of any of the other time-outs for the Application Server and Web Server.   Documents on Metalink often suggest 5 or 10 minutes, and I don't think that is unreasonable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;My thanks to Colin Kilpatrick who prompted me to look at this again.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-3231799605698304596?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/miRAcDFRyGE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/miRAcDFRyGE/oracle-terminated-connection-timeout.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/07/oracle-terminated-connection-timeout.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-6355404204789194109</guid><pubDate>Mon, 06 Jul 2009 21:48:00 +0000</pubDate><atom:updated>2009-09-22T22:05:40.656+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">global temporary tables</category><category domain="http://www.blogger.com/atom/ns#">Restartability</category><category domain="http://www.blogger.com/atom/ns#">Application Engine</category><title>Dynamically Switching PeopleSoft Temporary Records between Global Temporary and Normal Tables during Application Engine Programs</title><description>I am working on a Time &amp;amp; Labour system. We run the main T&amp;amp;L process in different modes. There is a company wide overnight batch process, but individual parts of the company can run the process for their section during the day to process exceptions and to generate schedules. This is done with a custom AE program that calls the delivered TL_TIMEADMIN.&lt;br /&gt;&lt;br /&gt;Running on Oracle 10gR2, we have faced performance problems caused by contention between concurrent truncate operations in these processes (see &lt;a href="http://blog.psftdba.com/2009/01/performance-implications-of-concurrent.html"&gt;Factors Affecting Performance of Concurrent Truncate of Working Storage Tables&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;One way to evade this problem is to convert the working storage tables to be Global Temporary Tables (GTTs).  The contention problem caused by serialisation of truncate operations does not occur with GTTs.  Last year I wrote a blog entry (&lt;a href="http://blog.psftdba.com/2008/01/global-temporary-tables-and-peoplesoft.html"&gt;Global Temporary Tables and PeopleSoft Temporary Records&lt;/a&gt;) that discussed when it was possible to use GTTs in Application Engine (AE) programs. Essentially, you can only use GTTs when restart is disabled for all AE programs that reference a temporary records.&lt;br /&gt;&lt;br /&gt;So we could consider running the small but frequent daytime processes with restart disabled. Then we can make the non-shared instances of the temporary records into Global Temporary tables for the non-restartable daytime processes. However, we want to continue to run the overnight processes with restart enabled so that we have the option to restart a process that fails overnight from where it crashed, rather than going back to the beginning. The same non-shared instances may need to be Global Temporary during the day but normal recoverable tables by night.&lt;br /&gt;&lt;br /&gt;Previously, I have only converted tables to Global Temporary where they are not referenced by a restartable AE program.  I have now devised a way of switching a table to being a GTT if it is allocated to a process for which restart is disabled, and switching it back to a normal table if not. This is the best of both worlds.&lt;br /&gt;&lt;br /&gt;When a non-shared instance of a temporary record is allocated to a particular process instance, a row is inserted into PS_AETEMPTBLMGR. The value of the restart disable flag is also stored in PS_AETEMPTBLMGR. I have created a &lt;a target="blank" href="http://www.go-faster.co.uk/scripts.htm#gfc_temp_table_type.sql"&gt;trigger&lt;/a&gt; that switches a non-shared instance of a temporary record from a normal table to a GTT if restart is disabled, or switches it back to a normal table if restart is enabled. The trigger will create the GTT and any indexes on it if necessary, and will rename the tables as necessary so that the correct version has the default name expected by the process.&lt;br /&gt;&lt;br /&gt;So if, for example, I have instance number 11 of a record called WRK_SHIFT_TAO, then the table will be called PS_WRK_SHIFT_TAO11. If that is allocated to a non-restartable AE program, the trigger will check for a table called GT_WRK_SHIFT_TAO11. If it doesn't exist the trigger will create it, dynamically generating the DDL with the &lt;a target="blank" href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_metada.htm#i1019414"&gt;dbms_metadata&lt;/a&gt; package. Thus, the structure of the GTT will be identical to PS_WRK_SHIFT_TAO11, the leading PS will also be changed to GT. The same indexes will also be created. The original normal table PS_WRK_SHIFT_TAO11 will be renamed to XX_WRK_SHIFT_TAO11, and then the GTT, at that point called GT_WRK_SHIFT_TAO11 will be renamed to PS_WRK_SHIFT_TAO11. The indexes are not renamed. If later the same instance is allocated to a restartable process, the change will be reversed by renaming again.  The GTT will not be dropped so that it does not need to be recreated again the next time the non-restartable program uses it.&lt;br /&gt;&lt;br /&gt;&lt;a target="blank" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_SlmmwRbAUdk/SlJzW8vcYmI/AAAAAAAAALA/AFHINGl3Luw/s1600-h/gfc_temp_table_type.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 164px; height: 200px;" src="http://4.bp.blogspot.com/_SlmmwRbAUdk/SlJzW8vcYmI/AAAAAAAAALA/AFHINGl3Luw/s200/gfc_temp_table_type.JPG" alt="" id="BLOGGER_PHOTO_ID_5355469744996377186" border="0" /&gt;&lt;/a&gt;All DDL generated and executed by the trigger is written to the Message Log for that process (click on the screen shot to enlarge).&lt;br /&gt;&lt;br /&gt;The shared instance of a record (the one without a instance number suffix) is never rebuilt as a Global Temporary table because it is possible that a restartable and non-restartable process might both use the shared instance at the same time.&lt;br /&gt;&lt;br /&gt;One complication is how to handle changes to the temporary records. Application Designer will only create normal tables. So, if the table is to be rebuilt, them it needs to be switched back to a normal table, and the corresponding GTT created by the trigger should then be dropped. The Application Designer can recreate the table in the usual way. Next time the non-restartable AE runs, it will recreate the GTT with the new structure.&lt;br /&gt;&lt;br /&gt;An updated version of &lt;a href="http://www.go-faster.co.uk/scripts.htm#t_lock.sql"&gt;T_LOCK&lt;/a&gt; is available which handles PeopleSoft temporary records and prevent DDL on PS_ tables with corresponding GT_ tables.  The commands which swap these tables back and forth are explicitly permitted by the new version of this trigger.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-6355404204789194109?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/YN8goos9sfQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/YN8goos9sfQ/dynamically-switching-peoplesoft.html</link><author>info@go-faster.co.uk (David Kurtz)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_SlmmwRbAUdk/SlJzW8vcYmI/AAAAAAAAALA/AFHINGl3Luw/s72-c/gfc_temp_table_type.JPG" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/07/dynamically-switching-peoplesoft.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-1282014570530371387</guid><pubDate>Thu, 25 Jun 2009 19:30:00 +0000</pubDate><atom:updated>2009-07-16T11:41:50.096+01:00</atom:updated><title>Controlling  How %UpdateStats Collects Optimizer Statistics</title><description>I have written a number of entries on this blog about updating database statistics on tables during Application Engine processes.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.psftdba.com/2009/04/statistics-management-for-peoplesoft.html"&gt;Statistics Management for PeopleSoft Temporary Records in Application Engine Programs&lt;/a&gt;, discussed management of statistics on GTTs, and the use of Optimizer Dynamic sampling.  &lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.psftdba.com/2009/04/statistics-management-for-partitioned.html"&gt;Statistics Management for Partitioned Objects in PeopleSoft&lt;/a&gt; discussed an enhancement to the wrapper so that it only gathered stale statistics on partitioned objects.  &lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.psftdba.com/2007/05/updatestats-v-optimizer-dynamic.html"&gt;%UpdateStats() -v- Optimizer Dynamic Sampling&lt;/a&gt; noted that I had found some situations where Oracle's Optimizer Dynamic Sampling, even at the highest level, does not produce the best execution plan and there is no alternative but to collect statistics on temporary tables.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I proposed a PL/SQL package (&lt;a target="blank" href="http://www.go-faster.co.uk/scripts.htm#ddlmodel"&gt;wrapper.sql&lt;/a&gt;) called from the DDL model to intercept the call from the %UpdateStats macro in Application Engine.  By default it&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Gathers statistics on regular tables.&lt;/li&gt;&lt;li&gt;Refreshed only stale statistics on partitioned tables.&lt;/li&gt;&lt;li&gt;Does not gather statistics on Global Temporary Records.&lt;/li&gt;&lt;/ul&gt;I have now published an enhanced version: &lt;a target="blank" href="http://www.go-faster.co.uk/script.htm#wrapper848meta.sql"&gt;wrapper848meta.sql&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A table PS_GFC_STATS_OVRD holds meta-data to override the default behaviour of the script for certain records. The meta-data can also specify the size of the sample, and the options to control the collection of histograms.&lt;/li&gt;&lt;li&gt;If a private instance of a Temporary Records is a Global Temporary Tables, the wrapper may still collect statistics (normally this would be suppressed because of the risk of one session using the statistics collected by another session, but this will not happen for these tables).&lt;/li&gt;&lt;/ul&gt;Now, it is possible to specify the few tables where statistics must still be explicitly gathered, or whether to do this only if the current statistics on the table are stale.  The DBA is probably the person best placed to decide whether and how to collect statistics on which tables, and these decisions can be implemented with the meta-data, but without code change.&lt;br /&gt;&lt;br /&gt;Thus, it is possible to&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Reduce the number of calls to dbms_stats, &lt;/li&gt;&lt;li&gt;to reduce the overhead of the remaining calls&lt;/li&gt;&lt;li&gt;and at least preserve, if not improve performance of batch processes without making any code changes.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-1282014570530371387?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/9d5fqfhzOOY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/9d5fqfhzOOY/controlling-how-updatestats-collects.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/06/controlling-how-updatestats-collects.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-8339463468628673959</guid><pubDate>Thu, 25 Jun 2009 19:23:00 +0000</pubDate><atom:updated>2009-06-30T13:30:26.553+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Oracle 10g</category><category domain="http://www.blogger.com/atom/ns#">Statistics Retention</category><category domain="http://www.blogger.com/atom/ns#">Optimizer Dynamic Sampling</category><title>Oracle 10g Statistics History Retention in PeopleSoft</title><description>I have been working on a system where many Application Engine programs are running throughout the day, and are frequently collecting Optimizer statistics with the &lt;span style="font-style: italic;"&gt;%UpdateStats&lt;/span&gt; macro on many working storage tables.  Concurrent calls to &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; are typical.&lt;br /&gt;&lt;br /&gt;There are two new behaviours in Oracle 10g RDBMS that can in extreme cases, in combination with a system that calls &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; very frequently, create a significant performance overhead.&lt;br /&gt;&lt;br /&gt;From Oracle 10g, histograms may, by default, be collected automatically.  That means that rows are concurrently deleted from and inserted into &lt;span style="font-style: italic;"&gt;histgrm$&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;hist_head$&lt;/span&gt;, leading to contention and consistent read.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Also from Oracle 10g, every time you collect statistics on a table the old statistics are retained in the &lt;span style="font-style: italic;"&gt;SYS.WRI$_OPTSTAT%HISTORY&lt;/span&gt; tables.  If histograms have previously been collected, these are also copied.  DBMS_STATS has the additional overhead of writing this history.  I found in excess of 10,000 versions of previous statistics for some tables, because the batch processes have updated statistics on working storage tables that many times.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; also appears to be responsible for purging history older than the retention limit.  The default retention period is 31 days.  I have seen concurrent calls to &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; blocked on row level locks on the statistics history tables.  For me, this occurred 31 days after the system went live on a significantly increased volume.&lt;/li&gt;&lt;/ul&gt;Statistics history was designed to work in conjunction with schema wide statistics jobs that only refreshed stale statistics.  There is an option on &lt;span style="font-style: italic;"&gt;gather_schema_stats&lt;/span&gt; to collect only statistics on tables where the current statistics are stale.  However, there is no such option on &lt;span style="font-style: italic;"&gt;gather_table_stats&lt;/span&gt;. If you have decided to call this procedure for a particular table, then it is assumed you know you need to refresh the statistics.  However, by calling &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; from a batch program you can end up calling it much more frequently than is really necessary.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Recommendations&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Disable statistics history by setting the retention period to zero.  Unfortunately this can only be set at database level.  The statistics history is there in case you want to revert to a previous version of the statistics should a new set of statistics produce a problem, but it is only used rarely, and I think this is a necessary sacrafice.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Use Oracle &lt;a target="blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/stats.htm#i43032"&gt;Optimizer Dynamic Sampling&lt;/a&gt;. However, I suggest increasing the level from the default of 2 to 4 to increase the situations in which it is used.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Introduce the new version of the &lt;a target="blank" href="http://www.go-faster.co.uk/scripts.htm#wrappermeta848.sql"&gt;PL/SQL wrapper package for &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt;&lt;/a&gt; so that you can specify the records for which statistics will be explicitly collected, and whether histograms are to be collect.  Thus you can reduce the number of calls to &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-8339463468628673959?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/oAOKdG6j5mM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/oAOKdG6j5mM/oracle-10g-statistics-history-retention.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/06/oracle-10g-statistics-history-retention.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-410767148542670863</guid><pubDate>Tue, 19 May 2009 10:30:00 +0000</pubDate><atom:updated>2009-05-29T09:51:05.193+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">PeopleTools 8.1x</category><category domain="http://www.blogger.com/atom/ns#">Tuxedo</category><title>Manually Booting Tuxedo Application Server Processes in Parallel</title><description>Normally when an Application Server is booted, initialisation of each process completes before the next one is started.  The ability to boot Application Server processes in parallel was added to the &lt;span style="font-style: italic;"&gt;psadmin&lt;/span&gt; utility in PeopleTools 8.48.  However, &lt;span style="font-style: italic;"&gt;psadmin&lt;/span&gt; is merely a wrapper for the BEA Tuxedo &lt;span style="font-style: italic;"&gt;tmadmin &lt;/span&gt;command line utility, and it has always been possible to do this manually in previous versions of PeopleTools via the &lt;span style="font-style: italic;"&gt;tmadmin &lt;/span&gt;utility as follows.&lt;br /&gt;&lt;br /&gt;1. Boot the Tuxedo Bulletin Board Liaison process.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;#boot the Tuxedo administrative processes&lt;br /&gt;boot -A&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;2. Boot the PeopleSoft Application Server processes and but specify the &lt;span style="font-style: italic;"&gt;-w&lt;/span&gt; parameter so that they don't wait as they start&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;boot -g APPSRV -w&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If you are running PUBSUB or other servers in other groups then you would also boot them here.&lt;br /&gt;&lt;br /&gt;3. Boot the JREPSRV process (which maps Java Classes to Tuxedo Services).&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;boot -g JREPGRP&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;4. List the servers with print server so you know that the PeopleSoft servers are booted.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;psr&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;5. When all the other processes have booted, boot the WSL and JSL processes.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;boot -g BASE&lt;br /&gt;boot -g JSLGRP&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-410767148542670863?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/B4OR3_2-bFQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/B4OR3_2-bFQ/manually-booting-tuxedo-application.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/05/manually-booting-tuxedo-application.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-5585053716472368597</guid><pubDate>Wed, 13 May 2009 06:00:00 +0000</pubDate><atom:updated>2009-05-21T23:17:46.499+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">SQL Tuning</category><category domain="http://www.blogger.com/atom/ns#">Performance Monitor</category><category domain="http://www.blogger.com/atom/ns#">Conference</category><category domain="http://www.blogger.com/atom/ns#">PeopleSoft Temporary Records</category><title>UKOUG PeopleSoft Conference 2009 Presentations</title><description>&lt;a target="_blank" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://peoplesoft.ukoug.org/"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 210px; height: 62px;" src="http://www.oug.org/images/imspeakingatsmall.jpg" alt="" border="0" /&gt;&lt;/a&gt;The &lt;a target="_blank" href="http://peoplesoft.ukoug.org/"&gt;2009 conference &lt;/a&gt;is past, but the &lt;a target="_blank" href="http://peoplesoft.ukoug.org/default.asp?p=2894"&gt;agenda&lt;/a&gt; is still available on the UKOUG webiste, and if you are a UKOUG member or attended the conference, you can download the presentations.&lt;br /&gt;&lt;br /&gt;I will be gave two new presentations that are on my website.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/psftpres.htm#PSTempRecs"&gt;Optimal Performance with PeopleTools Temporary Records&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/psftpres.htm#PracticalPPM2009"&gt;Practical Guidance on the Use of PeopleSoft Performance Monitor&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-5585053716472368597?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/ht41FkswHps" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/ht41FkswHps/ukoug-peoplesoft-conference-2009.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/05/ukoug-peoplesoft-conference-2009.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-3451465819945962958</guid><pubDate>Wed, 22 Apr 2009 08:08:00 +0000</pubDate><atom:updated>2009-09-22T21:49:13.833+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Application Engine</category><category domain="http://www.blogger.com/atom/ns#">Temporary Records</category><title>Reducing Unnecessary Instances of Temporary Records</title><description>In a &lt;a href="http://blog.psftdba.com/2009/01/performance-implications-of-concurrent.html"&gt;previous posting&lt;/a&gt;, I recommended moving temporary records used by Application Engine programs to a tablespace with a 32Kb block size, and using a larger uniform extent size (I chose 1Mb).&lt;br /&gt;&lt;br /&gt;However, continuing the example for my &lt;a href="http://blog.psftdba.com/2009/01/managing-changes-to-number-of-instances.html"&gt;last posting on this subject&lt;/a&gt;, TL_TIMEADMIN has 150 temporary records, that have 173 indexes (in HCM8.9).  So you get 323 segments for every instance set in the Application Engine properties, and that would consume at least 323Mb of the 32Kb tablespace.  If that space consumption is not a problem, then stop reading now.&lt;br /&gt;&lt;br /&gt;However, I noticed that some temporary records are used by several Application Engine programs.  This is usually because one program call another and the temporary records are referenced in both.  However if both programs have a number of instances of temporary records defined in their properties, then temporary tables will be built for both.&lt;br /&gt;&lt;br /&gt;Lets take an example TL_PUB_TM_AE calls TL_PUB_TM1.  They are both delivered with 5 instances.&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 100%; overflow: auto; border: 0px solid #000000; padding-left: 4px; padding-right: 4px; background-color:#EEEEEE"&gt;&lt;pre style="font-family:courier new;font-size:85%;"&gt;AE_APPLID    TEMPTBLINSTANCES&lt;br /&gt;------------ ----------------&lt;br /&gt;TL_PUB_TM1                  5&lt;br /&gt;TL_PUB_TM_AE                5&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;They share 8 temporary records in common.&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 100%; overflow: auto; border: 0px solid #000000; padding-left: 4px; padding-right: 4px; background-color:#EEEEEE"&gt;&lt;pre style="font-family:courier new;font-size:85%;"&gt;SELECT a.recname, a.ae_applid, b.ae_applid&lt;br /&gt;FROM  psaeappltemptbl a&lt;br /&gt; FULL OUTER JOIN psaeappltemptbl b&lt;br /&gt; ON  a.recname = b.recname&lt;br /&gt; AND b.ae_applid = 'TL_PUB_TM_AE'&lt;br /&gt;WHERE a.ae_applid = 'TL_PUB_TM1'&lt;br /&gt;ORDER BY 1&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;RECNAME         AE_APPLID    AE_APPLID&lt;br /&gt;--------------- ------------ ------------&lt;br /&gt;TL_PROF_LIST    TL_PUB_TM1&lt;br /&gt;TL_PROF_WRK     TL_PUB_TM1&lt;br /&gt;WRK_PROJ1_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ2_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ3_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ4_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ5_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ6_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ7_TAO   TL_PUB_TM1   TL_PUB_TM_AE&lt;br /&gt;WRK_PROJ_TAO    TL_PUB_TM1   TL_PUB_TM_AE&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;5 temporary records are built by Application Designer for each Application Engine program.  But TL_PUB_TM1 is never run on its own.  So do you need the extra instances of those 8 temporary records?  The temporary records defined on TL_PUB_TM_AE are a subset of TL_PUB_TM1.  If you reduced the number of instances on TL_PUB_TM_AE to 0, you would still have the 5 instances defined on TL_PUB_TM_TM1.  But that would enable you to drop 40 tables and their indexes.&lt;br /&gt;&lt;br /&gt;So, I started to wonder if there was a general principle here.  If the temporary tables on an Application Engine program are a subset of those on another program, then providing you make ensure the number of instances on the superset is not less than those of the subset, you could reduce the number of instances on the subset to 0.&lt;br /&gt;&lt;br /&gt;This view reports Application Engine programs whose temporary records are a subset of those on another program, and also counts the number of records in the subset.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE OR REPLACE VIEW gfc_aetemptbl_hier AS&lt;br /&gt;SELECT&lt;br /&gt;sup.ae_applid sup_applid, supa.temptblinstances sup_instances&lt;br /&gt;,  sub.ae_applid sub_applid, suba.temptblinstances sub_instances&lt;br /&gt;, (SELECT COUNT(*)&lt;br /&gt;FROM   psaeappltemptbl supc, psaeappltemptbl subc&lt;br /&gt;WHERE  supc.ae_applid = sup.ae_applid&lt;br /&gt;AND    subc.ae_applid = sub.ae_applid&lt;br /&gt;AND    subc.recname = supc.recname) num_records&lt;br /&gt;FROM (SELECT DISTINCT ae_applid FROM psaeappltemptbl) sup&lt;br /&gt;, (SELECT DISTINCT ae_applid FROM psaeappltemptbl) sub&lt;br /&gt;, psaeappldefn supa&lt;br /&gt;, psaeappldefn suba&lt;br /&gt;WHERE sup.ae_applid != sub.ae_applid&lt;br /&gt;AND supa.ae_applid = sup.ae_applid&lt;br /&gt;AND suba.ae_applid = sub.ae_applid&lt;br /&gt;AND EXISTS( /*a temporary record in common*/&lt;br /&gt;SELECT 'x'&lt;br /&gt;FROM psaeappltemptbl sup1&lt;br /&gt;, psaeappltemptbl sub1&lt;br /&gt;WHERE sub1.ae_applid = sub.ae_applid&lt;br /&gt;AND sup1.ae_applid = sup.ae_applid&lt;br /&gt;AND sup1.recname = sub1.recname&lt;br /&gt;AND ROWNUM = 1)&lt;br /&gt;/*there is no record in the subset that is not in the superset*/&lt;br /&gt;AND NOT EXISTS(&lt;br /&gt;SELECT  'x'&lt;br /&gt;FROM psaeappltemptbl sub2&lt;br /&gt;WHERE   sub2.ae_applid = sub.ae_applid&lt;br /&gt;AND NOT EXISTS(&lt;br /&gt; SELECT  'x'&lt;br /&gt; FROM psaeappltemptbl sup2&lt;br /&gt; WHERE   sup2.ae_applid = sup.ae_applid&lt;br /&gt; AND sub2.recname = sup2.recname&lt;br /&gt; AND ROWNUM = 1)&lt;br /&gt;AND ROWNUM = 1)&lt;br /&gt;/*there is a record in the subset that is not in the subset - so there is a difference*/&lt;br /&gt;AND EXISTS(&lt;br /&gt;SELECT  'x'&lt;br /&gt;FROM psaeappltemptbl sup2&lt;br /&gt;WHERE   sup2.ae_applid = sup.ae_applid&lt;br /&gt;AND NOT EXISTS(&lt;br /&gt; SELECT  'x'&lt;br /&gt; FROM psaeappltemptbl sub2&lt;br /&gt; WHERE   sub2.ae_applid = sub.ae_applid&lt;br /&gt; AND sup2.recname = sub2.recname&lt;br /&gt; AND ROWNUM = 1)&lt;br /&gt;AND ROWNUM = 1)&lt;br /&gt;ORDER BY 1,2;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This is the output from the view for the Application Engine programs in the example.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;SUP_APPLID   SUP_INSTANCES SUB_APPLID   SUB_INSTANCES NUM_RECORDS&lt;br /&gt;------------ ------------- ------------ ------------- -----------&lt;br /&gt;…&lt;br /&gt;TL_PUB_TM1               5 TL_PUB_TM_AE             5           8&lt;br /&gt;TL_PUB_TM1               5 TL_PY_PUB_TM             5           5&lt;br /&gt;TL_PUB_TM_AE             5 TL_PY_PUB_TM             5           5&lt;br /&gt;…&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I found that some Application Engine programs have identical sets of temporary records.  This can happen when a program is cloned, which some customers do when they want to customise a vanilla program.  This view reports on them.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE OR REPLACE VIEW gfc_aetemptbl_eq AS&lt;br /&gt;SELECT sup.ae_applid sup_applid, supa.temptblinstances sup_instances&lt;br /&gt;, sub.ae_applid sub_applid, suba.temptblinstances sub_instances&lt;br /&gt;, (SELECT COUNT(*)&lt;br /&gt;FROM   psaeappltemptbl supc, psaeappltemptbl subc&lt;br /&gt;WHERE  supc.ae_applid = sup.ae_applid&lt;br /&gt;AND    subc.ae_applid = sub.ae_applid&lt;br /&gt;AND    subc.recname = supc.recname) num_records&lt;br /&gt;FROM (SELECT DISTINCT ae_applid FROM psaeappltemptbl) sup&lt;br /&gt;, (SELECT DISTINCT ae_applid FROM psaeappltemptbl) sub&lt;br /&gt;, psaeappldefn supa&lt;br /&gt;, psaeappldefn suba&lt;br /&gt;WHERE sup.ae_applid &lt; ae_applid =" sup.ae_applid" ae_applid =" sub.ae_applid" ae_applid =" sub.ae_applid" ae_applid =" sup.ae_applid" recname =" sub1.recname" rownum =" 1)" ae_applid =" sub.ae_applid" ae_applid =" sup.ae_applid" recname =" sup2.recname" rownum =" 1)" rownum =" 1)" ae_applid =" sup.ae_applid" ae_applid =" sub.ae_applid" recname =" sub2.recname" rownum =" 1)" rownum =" 1)"&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Here, three programs share the same set of temporary records.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;SUP_APPLID   SUP_INSTANCES SUB_APPLID   SUB_INSTANCES NUM_RECORDS&lt;br /&gt;------------ ------------- ------------ ------------- -----------&lt;br /&gt;…&lt;br /&gt;ELEC_TSCRPT             20 E_TSCRPT_BAT            20           2&lt;br /&gt;ELEC_TSCRPT             20 E_TSCRPT_LIB            20           2&lt;br /&gt;E_TSCRPT_BAT            20 E_TSCRPT_LIB            20           2&lt;br /&gt;…&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I can use these view to set the instances on the subsets to 0 and increase the instances on the supersets as necessary.  There are examples of both subsets within subsets and more than two Application Engine programs that share the same set of temporary tables.  So I do this repeatedly until all the subsets have zero instances.&lt;br /&gt;&lt;br /&gt;This PL/SQL script makes the updates to the Application Engine programs (including maintaining PeopleSoft version numbers), and also creates an Application Designer project called GFC_TTI with all the programs and records.  This project can then be used to migrate the Application Engine programs to another environment.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;DECLARE&lt;br /&gt;l_any BOOLEAN;&lt;br /&gt;l_projectname VARCHAR2(30 CHAR) := 'GFC_TTI';&lt;br /&gt;l_version_aem INTEGER;&lt;br /&gt;l_version_pjm INTEGER;&lt;br /&gt;&lt;br /&gt;PROCEDURE projitem(objecttype   INTEGER&lt;br /&gt;           ,objectid1    INTEGER&lt;br /&gt;           ,objectvalue1 VARCHAR2) IS&lt;br /&gt;BEGIN&lt;br /&gt;INSERT INTO psprojectitem&lt;br /&gt;(projectname ,objecttype&lt;br /&gt;,objectid1 ,objectvalue1 ,objectid2 ,objectvalue2&lt;br /&gt;,objectid3 ,objectvalue3 ,objectid4 ,objectvalue4&lt;br /&gt;,nodetype ,sourcestatus ,targetstatus ,upgradeaction ,takeaction ,copydone)&lt;br /&gt;VALUES&lt;br /&gt;(l_projectname,objecttype&lt;br /&gt;,objectid1, objectvalue1, 0, ' '&lt;br /&gt;, 0, ' ', 0, ' '&lt;br /&gt;,0,0,0,0,1,0);&lt;br /&gt;EXCEPTION WHEN dup_val_on_index THEN NULL;&lt;br /&gt;END;&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;UPDATE psversion&lt;br /&gt;SET version = version+1&lt;br /&gt;WHERE objecttypename IN('SYS','AEM','PJM');&lt;br /&gt;&lt;br /&gt;UPDATE pslock&lt;br /&gt;SET version = version+1&lt;br /&gt;WHERE objecttypename IN('SYS','AEM','PJM');&lt;br /&gt;&lt;br /&gt;SELECT version&lt;br /&gt;INTO   l_version_aem&lt;br /&gt;FROM   psversion&lt;br /&gt;WHERE  objecttypename = 'AEM';&lt;br /&gt;&lt;br /&gt;SELECT version&lt;br /&gt;INTO   l_version_pjm&lt;br /&gt;FROM   psversion&lt;br /&gt;WHERE  objecttypename = 'PJM';&lt;br /&gt;&lt;br /&gt;l_any := TRUE;&lt;br /&gt;WHILE l_any LOOP&lt;br /&gt;l_any := FALSE;&lt;br /&gt;FOR i IN(&lt;br /&gt; SELECT *&lt;br /&gt; FROM gfc_aetemptbl_hier a&lt;br /&gt; WHERE a.sub_instances &gt; 0&lt;br /&gt; AND NOT EXISTS(&lt;br /&gt;  SELECT 'x'&lt;br /&gt;  FROM   gfc_aetemptbl_hier b&lt;br /&gt;  WHERE  b.sup_applid = a.sub_applid&lt;br /&gt;  AND    b.sub_instances &gt; 0&lt;br /&gt;  AND    ROWNUM = 1)&lt;br /&gt; ORDER BY 1&lt;br /&gt;) LOOP&lt;br /&gt; UPDATE psaeappldefn x&lt;br /&gt; SET    temptblinstances =     &lt;br /&gt;      GREATEST(x.temptblinstances&lt;br /&gt;              ,i.sub_instances,i.sup_instances)&lt;br /&gt; ,      version = l_version_aem&lt;br /&gt; ,      lastupddttm = SYSDATE&lt;br /&gt; WHERE  ae_applid = i.sup_applid; &lt;br /&gt;&lt;br /&gt; projitem(33,66,i.sup_applid);&lt;br /&gt;&lt;br /&gt; UPDATE psaeappldefn x&lt;br /&gt; SET    temptblinstances = 0&lt;br /&gt; ,    version = l_version_aem&lt;br /&gt; ,      lastupddttm = SYSDATE&lt;br /&gt; WHERE  ae_applid = i.sub_applid;&lt;br /&gt;&lt;br /&gt; projitem(33,66,i.sub_applid);&lt;br /&gt; l_any := TRUE;&lt;br /&gt;END LOOP;&lt;br /&gt;END LOOP;&lt;br /&gt;&lt;br /&gt;l_any := TRUE;&lt;br /&gt;WHILE l_any LOOP&lt;br /&gt;l_any := FALSE;&lt;br /&gt;FOR i IN(&lt;br /&gt; SELECT *&lt;br /&gt; FROM  gfc_aetemptbl_eq a&lt;br /&gt; WHERE a.sub_instances &gt; 0&lt;br /&gt; AND NOT EXISTS(&lt;br /&gt;  SELECT 'x'&lt;br /&gt;  FROM   gfc_aetemptbl_eq b&lt;br /&gt;  WHERE  b.sup_applid = a.sub_applid&lt;br /&gt;  AND    b.sub_instances &gt; 0&lt;br /&gt;  AND    ROWNUM = 1)&lt;br /&gt; ORDER BY 1&lt;br /&gt;) LOOP&lt;br /&gt; UPDATE psaeappldefn x&lt;br /&gt; SET    temptblinstances =     &lt;br /&gt;      GREATEST(x.temptblinstances&lt;br /&gt;              ,i.sub_instances,i.sup_instances)&lt;br /&gt; ,      version = l_version_aem&lt;br /&gt; ,      lastupddttm = SYSDATE&lt;br /&gt; WHERE  ae_applid = i.sup_applid;&lt;br /&gt;&lt;br /&gt; projitem(33,66,i.sub_applid);&lt;br /&gt;&lt;br /&gt; UPDATE psaeappldefn x&lt;br /&gt; SET    temptblinstances = 0&lt;br /&gt; ,      version = l_version_aem&lt;br /&gt; ,      lastupddttm = SYSDATE&lt;br /&gt; WHERE  ae_applid = i.sub_applid;&lt;br /&gt;&lt;br /&gt; projitem(33,66,i.sub_applid);&lt;br /&gt; l_any := TRUE;&lt;br /&gt;END LOOP;&lt;br /&gt;END LOOP;&lt;br /&gt;END;&lt;br /&gt;&lt;br /&gt;INSERT INTO psprojectitem&lt;br /&gt;(projectname ,objecttype&lt;br /&gt;,objectid1 ,objectvalue1 ,objectid2 ,objectvalue2&lt;br /&gt;,objectid3 ,objectvalue3 ,objectid4 ,objectvalue4&lt;br /&gt;,nodetype ,sourcestatus ,targetstatus ,upgradeaction ,takeaction ,copydone)&lt;br /&gt;SELECT DISTINCT&lt;br /&gt;l_projectname,0&lt;br /&gt;, 1, recname, 0, ' '&lt;br /&gt;, 0, ' ', 0, ' '&lt;br /&gt;, 0,0,0,0,1,0&lt;br /&gt;FROM   psaeappltemptbl t&lt;br /&gt;,      psprojectitem i&lt;br /&gt;WHERE  i.projectname  = l_projectname&lt;br /&gt;AND    i.objecttype   = 33&lt;br /&gt;AND    i.objectid1    = 66&lt;br /&gt;AND i.objectvalue1 = t.ae_applid&lt;br /&gt;AND NOT EXISTS(&lt;br /&gt;SELECT 'x'&lt;br /&gt;FROM   psprojectitem i1&lt;br /&gt;WHERE  i1.projectname = l_projectname&lt;br /&gt;AND    i1.objecttype  = 0&lt;br /&gt;AND    i1.objectid1   = 1&lt;br /&gt;AND    i1.objectvalue1 = t.recname&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;INSERT INTO psprojectdefn&lt;br /&gt;(projectname,version,projectdescr,tgtservername,tgtdbname&lt;br /&gt;,tgtoprid,tgtopracct,comprelease,srccompreldttm,tgtcompreldttm&lt;br /&gt;,compreldttm,keeptgt,tgtorientation,comparetype,commitlimit&lt;br /&gt;,reportfilter,maintproj,lastupddttm,lastupdoprid,releaselabel&lt;br /&gt;,releasedttm,objectownerid,descrlong)&lt;br /&gt;VALUES&lt;br /&gt;(l_projectname,l_version_pjm,'Temporary Table Instances',' ',' '&lt;br /&gt;,' ',' ',' ',NULL,NULL&lt;br /&gt;,NULL,31,0,1,50&lt;br /&gt;,16232832,0,SYSDATE,'PS',' '&lt;br /&gt;,NULL,' ','Application Engine programs, and related Temporary Records, '&lt;br /&gt; ||'whose number of temporary table instances have been changed');&lt;br /&gt;EXCEPTION WHEN dup_val_on_index THEN&lt;br /&gt;UPDATE psprojectdefn&lt;br /&gt;SET    version = (SELECT version FROM psversion&lt;br /&gt;                 WHERE  objecttypename = 'PJM')&lt;br /&gt;,      lastupddttm = SYSDATE&lt;br /&gt;WHERE  projectname = l_projectname;&lt;br /&gt;END;&lt;br /&gt;END;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The effect on my demo HCM8.9 system was to reduce the total number of temporary table instances from 5942 to 5106, a 14% reduction.  However, when I tried this on an HCM9.0 system, I got a reduction of only 7%.  This shows that PeopleSoft have been more careful about specifying the number of temporary tables in the later version.&lt;br /&gt;&lt;br /&gt;Then you can use the &lt;a href="http://blog.psftdba.com/2009/01/managing-changes-to-number-of-instances.html"&gt;script in an earlier posting&lt;/a&gt; to remove the excess tables.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-3451465819945962958?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/zWact_T2Oig" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/zWact_T2Oig/reducing-unnecessary-instances-of.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/04/reducing-unnecessary-instances-of.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-4729814106209241431</guid><pubDate>Mon, 06 Apr 2009 14:23:00 +0000</pubDate><atom:updated>2009-04-08T19:12:34.326+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DBMS_STATS</category><category domain="http://www.blogger.com/atom/ns#">Partitions</category><title>Statistics Management for Partitioned Objects in PeopleSoft</title><description>I have implemented partitioned objects in a number of PeopleSoft systems on Oracle. Recently, I was working on a system where a table was partitioned into weekly range partitions, and I encountered a performance problem when Oracle's automatic maintenance window job to collect statistics did not run between populating the new partition for the first time, and running a batch process that referenced that partition.  Oracle, understandably produced a execution plan for a statement that assumed the partition was empty, but as the partition actually had quite a lot of data, the statement ran for a long time.&lt;br /&gt;&lt;br /&gt;The solution was to tell Oracle the truth by gathering statistics for that partition.  However, I didn't want to refresh the statistics for the whole table.  There were many partitions with historical data that has not changed, so I don't need to refresh those partitions.  I only need to refresh just the stale partitions, and here is the problem.  Unfortunately, &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; package will let you gather stale and missing statistics for all tables in a given schema, or the whole database, but not for a named table.  It is not completely unreasonable, if you are targeting a single table then you ought to know what needs to be refreshed.&lt;br /&gt;&lt;br /&gt;I have written a PL/SQL procedure to flush the table monitoring statistics to the data dictionary and determine whether the statistics on the table, any of its partitions and sub-partitions are stale or missing, and if so gather statistics on those segments.  It uses (I believe) the same criteria as &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; to determine stale objects: 10% change relative to last gathered statistics, or if the segment has been truncated.  I have incorporated the new &lt;span style="font-style: italic;"&gt;refresh_stats&lt;/span&gt; procedure into my &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#ddlmodel"&gt;PL/SQL packaged procedure &lt;span style="font-style: italic;"&gt;wrapper&lt;/span&gt;&lt;/a&gt; which can be called by the &lt;span style="font-style: italic;"&gt;%UpdateStats&lt;/span&gt; PeopleCode macro via a customised DDL model.  The new procedure is only called for partitioned tables.&lt;br /&gt;&lt;br /&gt;All that is necessary it to use the &lt;span style="font-style: italic;"&gt;%UpdateStats&lt;/span&gt; macro in an Application Engine program.&lt;br /&gt;&lt;br /&gt;This is all still work-in-progress, but so far, the results are encouraging.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-4729814106209241431?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/c1vUDZ-ejro" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/c1vUDZ-ejro/statistics-management-for-partitioned.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/04/statistics-management-for-partitioned.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-5488747950482938823</guid><pubDate>Mon, 06 Apr 2009 13:39:00 +0000</pubDate><atom:updated>2009-04-07T08:29:04.957+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DBMS_STATS</category><category domain="http://www.blogger.com/atom/ns#">PeopleSoft Temporary Records</category><title>Statistics Management for PeopleSoft Temporary Records in Application Engine Programs</title><description>Last year, I wrote about &lt;a target="_blank" href="http://blog.psftdba.com/2008/06/oracle-optimizer-statistics-and.html"&gt;Oracle Optimizer Statistics and Optimizer Dynamic Sampling with PeopleSoft Temprorary Records&lt;/a&gt;.  Earlier this year, I encountered a situation where Optimizer Dynamic Sampling was not sufficient, and I did need properly gathered statistics on an object.  I modified my &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#ddlmodel"&gt;PL/SQL packaged procedure &lt;span style="font-style: italic;"&gt;wrapper&lt;/span&gt;&lt;/a&gt; which can be called by the %UpdateStats PeopleCode macro via a customised DDL model to collects statistics.&lt;br /&gt;&lt;br /&gt;I still recommend locking statistics on PeopleSoft Temporary Record, so that table is omitted from schema or database wide operations to refresh statistics.  If the statistics on a table are locked, and it is not a Global Temporary Table, then the &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#ddlmodel"&gt;&lt;span style="font-style: italic;"&gt;wrapper&lt;/span&gt;&lt;/a&gt; package will force collection and update of statistics on the table (previously it suppressed gathering of statistics on tables with locked statistics).&lt;br /&gt;&lt;br /&gt;However, when the Application Engine program completes, any statistics collected on those temporary tables are no longer needed.  Worse, the statistics refer to data that will be deleted and replaced by some future program, and if the table were not reanalysed, the statistics would be misleading, and could cause the database to produce an inappropriate execution plan.  Some temporary records are shared by multiple programs, so you cannot guarantee that statistics will always be refreshed when the table is next used.&lt;br /&gt;&lt;br /&gt;When an Application Engine program completes successfully, or when the process request is cancelled, specific instances of temporary records that were allocated when the program began are deallocated by deleting the row from PS_AETEMPTBLMGR.  Therefore, I propose the following trigger that will delete the statistics for that record when that row is deleted.&lt;br /&gt;&lt;a href="http://www.go-faster.co.uk/scripts.htm#deltempstats.sql"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;&lt;a href="http://www.go-faster.co.uk/scripts.htm#deltempstats.sql"&gt;CREATE OR REPLACE TRIGGER gfc_deletetemptablestats&lt;br /&gt;AFTER DELETE ON sysadm.ps_aetemptblmgr&lt;br /&gt;FOR EACH ROW&lt;br /&gt;WHEN (old.curtempinstance &gt; 0)&lt;br /&gt;DECLARE&lt;br /&gt;PRAGMA AUTONOMOUS_TRANSACTION;&lt;br /&gt;l_table_name VARCHAR2(30) := '';&lt;br /&gt;BEGIN&lt;br /&gt;SELECT DECODE(r.sqltablename,' ','PS_'||r.recname,r.sqltablename)||:old.curtempinstance tabname&lt;br /&gt;INTO   l_table_name&lt;br /&gt;FROM   psrecdefn r&lt;br /&gt;WHERE  r.recname = :old.recname;&lt;br /&gt;&lt;br /&gt;dbms_stats.delete_table_stats(ownname=&gt;'SYSADM',tabname=&gt;l_table_name,force=&gt;TRUE);&lt;br /&gt;&lt;br /&gt;EXCEPTION&lt;br /&gt;WHEN no_data_found THEN NULL;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;show errors&lt;/a&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;NB: The trigger must use an autonomous transaction because &lt;span style="font-style: italic;"&gt;dbms_stats&lt;/span&gt; also commits its updates.&lt;br /&gt;&lt;br /&gt;You can test the trigger like this: First I will populate the control table with a dummy record, and collect statistics&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;INSERT INTO ps_aetemptblmgr&lt;br /&gt;(PROCESS_INSTANCE, RECNAME, CURTEMPINSTANCE, OPRID, RUN_CNTL_ID, AE_APPLID&lt;br /&gt;,RUN_DTTM, AE_DISABLE_RESTART, AE_DEDICATED, AE_TRUNCATED)&lt;br /&gt;VALUES&lt;br /&gt;(0,'TL_EXCEPT_WRK',24,'PS','Wibble','TL_TIMEADMIN',sysdate,' ', 1,0)&lt;br /&gt;/&lt;br /&gt;execute dbms_stats.gather_table_stats(ownname=&gt;'SYSADM',tabname=&gt;'PS_TL_EXCEPT_WRK24',force=&gt;TRUE);&lt;br /&gt;&lt;br /&gt;column table_name format a18&lt;br /&gt;SELECT table_name, num_rows, last_analyzed&lt;br /&gt;FROM user_tables where table_name = 'PS_TL_EXCEPT_WRK24'&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;TABLE_NAME           NUM_ROWS LAST_ANALYZED&lt;br /&gt;------------------ ---------- -------------------&lt;br /&gt;PS_TL_EXCEPT_WRK24          0 14:36:12 06/04/2009&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Now I will delete the row, and the trigger will delete the statistics for me.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;DELETE FROM ps_aetemptblmgr&lt;br /&gt;WHERE process_instance = 0&lt;br /&gt;and curtempinstance = 24&lt;br /&gt;and recname = 'TL_EXCEPT_WRK'&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;SELECT table_name, num_rows, last_analyzed&lt;br /&gt;FROM user_tables where table_name = 'PS_TL_EXCEPT_WRK24'&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;TABLE_NAME           NUM_ROWS LAST_ANALYZED&lt;br /&gt;------------------ ---------- -------------------&lt;br /&gt;PS_TL_EXCEPT_WRK24&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-5488747950482938823?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/QKB_gw3nagk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/QKB_gw3nagk/statistics-management-for-peoplesoft.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/04/statistics-management-for-peoplesoft.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-4825816197248189548</guid><pubDate>Thu, 02 Apr 2009 19:19:00 +0000</pubDate><atom:updated>2009-04-02T20:28:41.214+01:00</atom:updated><title>Automatically Granting Privileges on Newly Created Tables (continued)</title><description>Following &lt;a target="_blank" href="http://blog.psftdba.com/2009/03/automatically-granting-privileges-on.html"&gt;this posting&lt;/a&gt; it was put to me that you could get Application Designer to build scripts with the commands to add the privilege by adding a second command to the create table DDL model, like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE TABLE [TBNAME] ([TBCOLLIST]) TABLESPACE [TBSPCNAME] STORAGE (INITIAL **INIT** NEXT **NEXT** MAXEXTENTS **MAXEXT** PCTINCREASE **PCT**) PCTFREE **PCTFREE** PCTUSED **PCTUSED**;&lt;br /&gt;GRANT SELECT ON [TBNAME] TO psreadall;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Yes, this does work when creating the table.  The additional command is put into the create table script generated by Application Designer&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;DROP TABLE PS_PERSON&lt;br /&gt;/&lt;br /&gt;CREATE TABLE PS_PERSON (EMPLID VARCHAR2(11) NOT NULL,&lt;br /&gt;BIRTHDATE DATE,&lt;br /&gt;BIRTHPLACE VARCHAR2(30) NOT NULL,&lt;br /&gt;BIRTHCOUNTRY VARCHAR2(3) NOT NULL,&lt;br /&gt;BIRTHSTATE VARCHAR2(6) NOT NULL,&lt;br /&gt;DT_OF_DEATH DATE,&lt;br /&gt;LAST_CHILD_UPDDTM DATE) TABLESPACE HRLARGE STORAGE (INITIAL 40000&lt;br /&gt;NEXT 100000 MAXEXTENTS UNLIMITED PCTINCREASE 0) PCTFREE 10 PCTUSED 80&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;GRANT SELECT ON PS_PERSON TO PSREADALL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;/&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;However, the second command &lt;span style="font-weight: bold;"&gt;does not &lt;/span&gt;appear in the alter script.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE TABLE PSYPERSON (EMPLID VARCHAR2(11) NOT NULL,&lt;br /&gt;BIRTHDATE DATE,&lt;br /&gt;BIRTHPLACE VARCHAR2(30) NOT NULL,&lt;br /&gt;BIRTHCOUNTRY VARCHAR2(3) NOT NULL,&lt;br /&gt;BIRTHSTATE VARCHAR2(6) NOT NULL,&lt;br /&gt;DT_OF_DEATH DATE,&lt;br /&gt;LAST_CHILD_UPDDTM DATE) TABLESPACE HRLARGE STORAGE (INITIAL 40000&lt;br /&gt;NEXT 100000 MAXEXTENTS UNLIMITED PCTINCREASE 0) PCTFREE 10 PCTUSED 80&lt;br /&gt;/&lt;br /&gt;INSERT INTO PSYPERSON (&lt;br /&gt;     EMPLID,&lt;br /&gt; BIRTHDATE,&lt;br /&gt; BIRTHPLACE,&lt;br /&gt; BIRTHCOUNTRY,&lt;br /&gt; BIRTHSTATE,&lt;br /&gt; DT_OF_DEATH,&lt;br /&gt; LAST_CHILD_UPDDTM)&lt;br /&gt;SELECT&lt;br /&gt;     EMPLID,&lt;br /&gt; BIRTHDATE,&lt;br /&gt; BIRTHPLACE,&lt;br /&gt; BIRTHCOUNTRY,&lt;br /&gt; BIRTHSTATE,&lt;br /&gt; DT_OF_DEATH,&lt;br /&gt; LAST_CHILD_UPDDTM&lt;br /&gt;FROM PS_PERSON&lt;br /&gt;/&lt;br /&gt;DROP TABLE PS_PERSON&lt;br /&gt;/&lt;br /&gt;RENAME PSYPERSON TO PS_PERSON&lt;br /&gt;/&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;So if you alter a table by create, rename and drop, you will lose the granted privileges.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-4825816197248189548?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/EMJwfjTTiqc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/EMJwfjTTiqc/automatically-granting-privileges-on.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/04/automatically-granting-privileges-on.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-9028954932483240940</guid><pubDate>Fri, 13 Mar 2009 11:17:00 +0000</pubDate><atom:updated>2009-09-22T21:57:07.473+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Oracle Enterprise Manager</category><category domain="http://www.blogger.com/atom/ns#">Grid Control</category><category domain="http://www.blogger.com/atom/ns#">DBMS_APPLICATION_INFO</category><title>Using Oracle Enterprise Manager (Grid Control) with PeopleSoft</title><description>If you use Oracle Grid Control to monitor your PeopleSoft system, here is a simple tip that will help you identify batch processes.&lt;br /&gt;&lt;br /&gt;Oracle provides two columns on the session information (v$session) to hold context information.  They provide a PL/SQL package &lt;a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm"&gt;DBMS_APPLICATION_INFO&lt;/a&gt;, which has procedures to read and update these values.  The idea is that application developers will instrument their programs and will update these values.  Oracle’s Applications (that it has developed itself), such as E-Business Suite do this.  PeopleSoft was rather slow to make use of this.  They do set the module and action, but not to very useful values.&lt;br /&gt;&lt;br /&gt;However, you can create a trigger on the Process Scheduler request table that will update these values when a process starts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;font-size:85%;"&gt;(Updated 19.4.2009) &lt;/span&gt;I have created a PL/SQL package &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#psftapi.sql"&gt;&lt;span style="font-style: italic;"&gt;psftapi&lt;/span&gt;&lt;/a&gt; that contains a number of procedure that I have used from triggers and other PL/SQL programs.  It contains a function that sets the ACTION for the session with the process instance and the description of the status.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#psftapi.sql"&gt;&lt;div style="width: 100%; overflow: auto; border: 0px solid #000000; padding-left: 4px; padding-right: 4px; background-color:#EEEEEE"&gt;&lt;pre style="font-family:courier new;font-size:85%;"&gt;...&lt;br /&gt;PROCEDURE set_action&lt;br /&gt;(p_prcsinstance INTEGER&lt;br /&gt;,p_runstatus VARCHAR2&lt;br /&gt;) IS&lt;br /&gt;l_runstatus VARCHAR2(10 CHAR);&lt;br /&gt;BEGIN&lt;br /&gt; BEGIN&lt;br /&gt;  SELECT x.xlatshortname&lt;br /&gt;  INTO   l_runstatus&lt;br /&gt;  FROM   psxlatitem x&lt;br /&gt;  WHERE  x.fieldname = 'RUNSTATUS'&lt;br /&gt;  AND    x.fieldvalue = p_runstatus&lt;br /&gt;  AND    x.eff_status = 'A'&lt;br /&gt;  AND    x.effdt = (&lt;br /&gt;   SELECT MAX(x1.effdt)&lt;br /&gt;   FROM   psxlatitem x1&lt;br /&gt;   WHERE  x1.fieldname = x.fieldname&lt;br /&gt;   AND    x1.fieldvalue = x.fieldvalue&lt;br /&gt;   AND    x1.effdt &lt;= SYSDATE);&lt;br /&gt; EXCEPTION &lt;br /&gt;  WHEN no_data_found THEN l_runstatus := 'Status:'||p_runstatus;       &lt;br /&gt; END;    &lt;br /&gt; sys.dbms_application_info.set_action(&lt;br /&gt;  action_name =&gt; SUBSTR('PI='||p_prcsinstance||':'||l_runstatus,1,32) );&lt;br /&gt;END set_action;&lt;br /&gt;...&lt;/pre&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This procedure can be called from a trigger thus:&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#psftapi.sql"&gt;&lt;div style="width: 100%; overflow: auto; border: 0px solid #000000; padding-left: 4px; padding-right: 4px; background-color:#EEEEEE"&gt;&lt;pre style="font-family:courier new;font-size:85%;"&gt;CREATE OR REPLACE TRIGGER sysadm.psftapi_store_prcsinstance&lt;br /&gt;BEFORE UPDATE OF runstatus ON sysadm.psprcsrqst&lt;br /&gt;FOR EACH ROW&lt;br /&gt;WHEN ((new.runstatus IN('3','7','8','9','10') OR&lt;br /&gt;     old.runstatus IN('7','8')) AND new.prcstype != 'PSJob')&lt;br /&gt;BEGIN&lt;br /&gt; IF :new.runstatus = '7' THEN&lt;br /&gt;  psftapi.set_prcsinstance(p_prcsinstance =&gt; :new.prcsinstance);&lt;br /&gt;  psftapi.set_action(p_prcsinstance=&gt;:new.prcsinstance&lt;br /&gt;                    ,p_runstatus=&gt;:new.runstatus&lt;br /&gt;                    ,p_prcsname=&gt;:new.prcsname);&lt;br /&gt; ELSIF psftapi.get_prcsinstance() = :new.prcsinstance THEN&lt;br /&gt;  psftapi.set_action(p_prcsinstance=&gt;:new.prcsinstance&lt;br /&gt;                    ,p_runstatus=&gt;:new.runstatus);&lt;br /&gt; END IF;&lt;br /&gt;EXCEPTION WHEN OTHERS THEN NULL; --exception deliberately coded to suppress all exceptions&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What is the benefit?  The MODULE and ACTION show up in Grid Control.  So now you can immediately identify the name and Process Instance of those expensive processes.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://go-faster.co.uk/images/oemgridact.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer; width: 75%; height: 75%;" src="http://go-faster.co.uk/images/oemgridact.png" alt="Screenshot from Oracle Enterprise Manager" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Unfortunately, it is not possible to do anything similar for sessions created by the Application Server.  So all you know is what session belongs to what kind of server process.  The Client Information is set at the top of each service, so you know the PeopleSoft Operator ID, but that is all.&lt;br /&gt;&lt;br /&gt;It would be useful nice if perhaps the Component name and PeopleCode context was written to MODULE and ACTION.  But it isn’t.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-9028954932483240940?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/kiHmj4TnhZg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/kiHmj4TnhZg/using-oracle-enterprise-manager-grid.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/03/using-oracle-enterprise-manager-grid.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-8681325713263750232</guid><pubDate>Thu, 12 Mar 2009 19:41:00 +0000</pubDate><atom:updated>2009-03-16T17:06:53.266Z</atom:updated><title>Minimum Number of Application Server Processes</title><description>I have had two conversations recently about what happens if you have only a single PSAPPSRV process in a domain.  One of which was on the &lt;a target="_blank" href="http://tech.groups.yahoo.com/group/psftdba/message/3651"&gt;DBA Forum&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Basically, &lt;span style="font-weight: bold;"&gt;you should always have at least two instances of any server process that has a non-zero recycle count&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;It is rare to see only one PSAPPSRV process in Application Server domains that support the PIA, but customers who use the Integration Broker often have separate Application Server domains for the publication and subscription servers.  These domains are often not heavily used, in which case they have been configured with just one of each server process.&lt;br /&gt;&lt;br /&gt;This advice applies to the PSAPPSRV, PSQRYSRV, PSBRKHND, PSSUBHND, PSANALYTICSRV servers&lt;br /&gt;&lt;br /&gt;The exceptions are&lt;br /&gt;&lt;ul&gt;&lt;li&gt;PSSAMSRV is only used by Windows clients in 3-tier mode (nVision and PS/Query)&lt;/li&gt;&lt;li&gt;PSMSGDSP, only a single process can be configured&lt;/li&gt;&lt;li&gt;PSAESRV, because in the Process Scheduler each PSAESRV has its own queue.&lt;/li&gt;&lt;/ul&gt;The problem occurs when the server process recycles.  This occurs when the number of services handled reaches the recycle count.  When the only remaining server process on a shared queue shuts down the queue is also deleted, and the advertised services are removed from the Tuxedo Bulletin Board.  If a service requests arrives in the application server domain before the new server process has started, and updated the bulletin board with advertised processes, the Jolt handler (JSH) will determine that the service request is not advertised and will raise an error.&lt;br /&gt;&lt;br /&gt;It is quite simple to demonstrate this in PeopleSoft.  In my demo system, I set the recycle count on PSAPPSRV to just 10 and the minimum number of servers to 1.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;[PSAPPSRV]&lt;br /&gt;;=========================================================================&lt;br /&gt;; Settings for PSAPPSRV&lt;br /&gt;;=========================================================================&lt;br /&gt;&lt;br /&gt;;-------------------------------------------------------------------------&lt;br /&gt;; UBBGEN settings&lt;br /&gt;Min Instances=1&lt;br /&gt;Max Instances=2&lt;br /&gt;Service Timeout=300&lt;br /&gt;&lt;br /&gt;;-------------------------------------------------------------------------&lt;br /&gt;; Number of services after which PSAPPSRV will automatically restart.&lt;br /&gt;; If the recycle count is set to zero, PSAPPSRV will never be recycled.&lt;br /&gt;; The default value is 5000.&lt;br /&gt;; Dynamic change allowed for Recycle Count&lt;br /&gt;Recycle Count=10&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;It is not long until the PSAPPSRV process recycles, and you get this message in the application server log.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;PSAPPSRV.2140 (10) [03/11/09 06:55:15 PTWEBSERVER@GO-FASTER-4](0) Recycling server after 10 services&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;You can also see in the shutdown message in the TUXLOG file.&lt;br /&gt;&lt;br /&gt;The last line is the error message from the JSH process that cannot enqueue the service request because the Application Server is down.  If you suspect that you have been getting this problem look for that error message.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;065655.GO-FASTER-4!BBL.2444.1760.0: LIBTUX_CAT:541: WARN: Server APPSRV/1 terminated&lt;br /&gt;065655.GO-FASTER-4!BBL.2444.1760.0: LIBTUX_CAT:550: WARN: Cleaning up restartable server APPSRV/1&lt;br /&gt;065655.GO-FASTER-4!cleanupsrv.1756.1204.-2: 03-11-2009: Tuxedo Version 8.1, 32-bit&lt;br /&gt;065655.GO-FASTER-4!cleanupsrv.1756.1204.-2: CMDTUX_CAT:542: ERROR: Cannot find service to which to forward request&lt;br /&gt;065655.GO-FASTER-4!cleanupsrv.1756.1204.-2: server APPSRV/1: CMDTUX_CAT:551: INFO: server removed&lt;br /&gt;065655.GO-FASTER-4!JSH.2192.4860.-2: JOLT_CAT:1043: "ERROR: tpcall() call failed, tperrno = 6"&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Hence, you should always have at least two PSAPPSRVs process, so that queue is not removed, and the other server(s) can handle requests.  Of course there is a small chance that two servers could recycle at the same time, but that is very unlikely.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-8681325713263750232?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/YEEp3Udcb1s" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/YEEp3Udcb1s/minimum-number-of-application-server.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/03/minimum-number-of-application-server.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-8017166761966953714</guid><pubDate>Thu, 05 Mar 2009 19:28:00 +0000</pubDate><atom:updated>2009-04-02T20:34:07.906+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Privileges</category><category domain="http://www.blogger.com/atom/ns#">DDL trigger</category><title>Automatically Granting Privileges on Newly Created Tables</title><description>I saw an interesting question on the &lt;a target="_blank" href="http://www.freelists.org/webpage/oracle-l"&gt;Oracle-L&lt;/a&gt; forum: &lt;a target="_blank" href="http://www.freelists.org/post/oracle-l/Access-to-temp-tables-created-dynamically"&gt;We have Peoplesoft applications that create tables on the fly. Developers want access to those tables that will be created on the fly, in case the process that creates it ends abnormally. I looked into granting via DDL triggers, it seemed like granting access via them is a problem. Is there a way to grant access other than doing 'grant select any'&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I am finding it increasingly common for developers and support staff not to have direct access to the PeopleSoft OwnerID schema (SYSADM) in even development environments, but using personal database logins.  They need to have SELECT privilege on tables.  The problem described above also occurs when table is rebuilt by Application Designer.  When it is dropped the granted privileges disappear with the table.&lt;br /&gt;&lt;br /&gt;It is certainly true that you cannot issue DDL in DDL trigger on the same object that caused the trigger to fire.  You will get an error caused by a deadlock in the recursive SQL.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE OR REPLACE TRIGGER gfc_grant AFTER CREATE ON sysadm.schema&lt;br /&gt;DECLARE&lt;br /&gt;l_cmd VARCHAR2(1000 CHAR);&lt;br /&gt;BEGIN&lt;br /&gt;IF ora_dict_obj_type = 'TABLE' THEN&lt;br /&gt;l_cmd := 'GRANT SELECT ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO gofaster';&lt;br /&gt;dbms_output.put_line('DDL:'||l_cmd);&lt;br /&gt;EXECUTE IMMEDIATE l_cmd;&lt;br /&gt;END IF;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;set serveroutput on&lt;br /&gt;DDL:GRANT SELECT ON SYSADM.T TO gofaster&lt;br /&gt;CREATE TABLE t (a NUMBER)&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-00604: error occurred at recursive SQL level 1&lt;br /&gt;ORA-30511: invalid DDL operation in system triggers&lt;br /&gt;ORA-06512: at line 9&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Some sites have regular maintenance jobs that recreate any missing privileges.&lt;br /&gt;&lt;br /&gt;However, there is a way to have the privileges automatically recreated soon after the table is built.  You could use a DDL trigger to submit a job to the Oracle job scheduler to grant the privileges.  You can't submit DDL directly via the job scheduler, so you need a procedure to which you can pass the DDL as a string parameter, and then execute it as dynamic SQL in the procedure.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE OR REPLACE PROCEDURE myddl&lt;br /&gt;(p_ddl IN VARCHAR2) IS&lt;br /&gt;BEGIN&lt;br /&gt;EXECUTE IMMEDIATE p_ddl;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then the DDL trigger can submit a job to call this procedure with the &lt;span style="font-style: italic;"&gt;GRANT&lt;/span&gt; command in the parameter.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE OR REPLACE TRIGGER gfc_grant&lt;br /&gt;AFTER CREATE ON sysadm.schema&lt;br /&gt;DECLARE&lt;br /&gt;l_jobno NUMBER;&lt;br /&gt;BEGIN&lt;br /&gt;IF ora_dict_obj_type = 'TABLE' THEN&lt;br /&gt;dbms_job.submit(l_jobno,'myddl(''GRANT SELECT ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO gofaster'');');&lt;br /&gt;END IF;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If I create this table&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;CREATE TABLE t (a NUMBER);&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I get this job&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;SELECT * FROM dba_jobs&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt; JOB LOG_USER&lt;br /&gt;---------- ------------------------------------------------------------------------------------------&lt;br /&gt;PRIV_USER&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;SCHEMA_USER                                                                                LAST_DATE&lt;br /&gt;------------------------------------------------------------------------------------------ -------------------&lt;br /&gt;LAST_SEC                 THIS_DATE           THIS_SEC                 NEXT_DATE&lt;br /&gt;------------------------ ------------------- ------------------------ -------------------&lt;br /&gt;NEXT_SEC                 TOTAL_TIME BRO&lt;br /&gt;------------------------ ---------- ---&lt;br /&gt;INTERVAL&lt;br /&gt;---------------------------------------------------------------------------------------------------------------&lt;br /&gt;FAILURES&lt;br /&gt;----------&lt;br /&gt;WHAT&lt;br /&gt;---------------------------------------------------------------------------------------------------------------&lt;br /&gt;  60 SYSADM&lt;br /&gt;SYSADM&lt;br /&gt;SYSADM&lt;br /&gt;                                                                19:04:52 05/03/2009&lt;br /&gt;19:04:52                          0 N&lt;br /&gt;null&lt;br /&gt;&lt;br /&gt;myddl('GRANT SELECT ON SYSADM.T TO gofaster');&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;After the job has run, which should normally only be a few seconds, I get these privileges&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;SELECT * FROM user_tab_privs WHERE table_name = 'T';&lt;br /&gt;&lt;br /&gt;GRANTEE&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;OWNER&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;TABLE_NAME&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;GRANTOR&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;PRIVILEGE&lt;br /&gt;---------------------------------------------------------------------------------------------------------------&lt;br /&gt;GOFASTER&lt;br /&gt;SYSADM&lt;br /&gt;T&lt;br /&gt;SYSADM&lt;br /&gt;SELECT&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Added 2.4.2009: &lt;/span&gt;Following this posting it was put to me that you could get Application Designer to build scripts with the commands to add the privilege by adding a second command to the create table DDL model.  &lt;a target="_blank" href="http://blog.psftdba.com/2009/04/automatically-granting-privileges-on.html"&gt;See part 2&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-8017166761966953714?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/miBxzSIeizU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/miBxzSIeizU/automatically-granting-privileges-on.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/03/automatically-granting-privileges-on.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-5642770847335457101</guid><pubDate>Fri, 27 Feb 2009 16:01:00 +0000</pubDate><atom:updated>2009-03-03T09:27:25.460Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">Parse</category><category domain="http://www.blogger.com/atom/ns#">ReUse Statement</category><category domain="http://www.blogger.com/atom/ns#">Application Engine</category><title>Performance Benefits of ReUse Statement Flag in Application Engine</title><description>I have achieved some significant performance improvements in some Application Engine programs by just enabling the ReUse Statement flag on certain steps.  I thought I would share a recent example of how effective this can be.&lt;br /&gt;&lt;br /&gt;I don't think I can improve on the description of this feature in PeopleBooks:&lt;br /&gt;&lt;a target="_blank" href="http://download.oracle.com/docs/cd/E13292_01/pt849pbr0/eng/psbooks/tape/chapter.htm?File=tape/htm/tape05.htm%23d0e4240"&gt;"One of the key performance features of PeopleSoft Application Engine is the ability to reuse SQL statements by dedicating a persistent cursor to that statement.&lt;br /&gt;&lt;br /&gt;Unless you select the ReUse property for a SQL action, %BIND fields are substituted with literal values in the SQL statement. The database has to recompile the statement every time it is executed.&lt;br /&gt;&lt;br /&gt;However, selecting ReUse converts any %BIND fields into real bind variables (:1, :2, and so on), enabling PeopleSoft Application Engine to compile the statement once, dedicate a cursor, and re-execute it with new data multiple times. This reduction in compile time can result in dramatic improvements to performance.&lt;br /&gt;&lt;br /&gt;In addition, some databases have SQL statement caching. Every time they receive SQL, they compare it against their cache of previously executed statements to see if they have seen it before. If so, they can reuse the old query plan. This works only if the SQL text matches exactly. This is unlikely with literals instead of bind variables."&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;In fact most databases do this, and Oracle certainly does.&lt;br /&gt;&lt;br /&gt;On Oracle, you could enable &lt;a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/memory.htm#i31512"&gt;CURSOR_SHARING&lt;/a&gt;.  Then Oracle effectively replaces the literals with bind variables at parse time.  However, I certainly would not recommend doing this database-wide.  Whenever I have tried this on a PeopleSoft system, it has had severe negative effects elsewhere.  I have enabled cursor sharing at session level for specific batch programs (using a trigger), but even then it is not always beneficial.&lt;br /&gt;&lt;br /&gt;Instead, I do recommend using the ReUse Statement flag wherever possible.  It cannot just be turned on indiscriminately, the same section in PeopleBooks goes on to describe some limitations (which is probably why the default value for the flag is false).&lt;br /&gt;&lt;br /&gt;To illustrate the kind of improvement you can obtain, here is a real-life example.  This is an extract from the batch timings report at the end of the Application Engine trace file.  We are interested in statements with the high compile count.&lt;br /&gt;&lt;br /&gt;ReUse Statement is not enabled on these 4 steps.  They account for more that 50% of the overall execution time.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre   style=";font-family:courier new;font-size:78%;"&gt;                          PeopleSoft Application Engine Timings&lt;br /&gt;                              (All timings in seconds)&lt;br /&gt;&lt;br /&gt;        C o m p i l e    E x e c u t e    F e t c h        Total&lt;br /&gt;SQL Statement                  Count   Time     Count   Time     Count   Time     Time&lt;br /&gt;------------------------------ ------- -------- ------- -------- ------- -------- --------&lt;br /&gt;99XxxXxx.Step02.S                 &lt;span style="font-weight: bold;text-decoration:underline"&gt;8453&lt;/span&gt;      2.8    8453    &lt;span style="font-weight: bold;text-decoration:underline"&gt;685.6&lt;/span&gt;       0      0.0    688.4&lt;br /&gt;99XxxXxx.Step03.S                 &lt;span style="font-weight: bold;text-decoration:underline"&gt;8453&lt;/span&gt;      5.0    8453   &lt;span style="font-weight: bold;text-decoration:underline"&gt;2718.8&lt;/span&gt;       0      0.0   2723.8&lt;br /&gt;99XxxXxx.Step05.S                 &lt;span style="font-weight: bold;text-decoration:underline"&gt;8453&lt;/span&gt;      0.9    8453    &lt;span style="font-weight: bold;text-decoration:underline"&gt;888.4&lt;/span&gt;       0      0.0    889.3&lt;br /&gt;99XxxXxx.Step06.S                 &lt;span style="font-weight: bold;text-decoration:underline"&gt;8453&lt;/span&gt;      0.4    8453     &lt;span style="font-weight: bold;text-decoration:underline"&gt;17.4&lt;/span&gt;       0      0.0     17.8&lt;br /&gt;&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;Total run time                :     &lt;span style="font-weight: bold;text-decoration:underline"&gt;8416.4&lt;/span&gt;&lt;br /&gt;Total time in application SQL :     8195.0   Percent time in application SQL :       97.4%&lt;br /&gt;Total time in PeopleCode      :      192.7   Percent time in PeopleCode      :        2.3%&lt;br /&gt;Total time in cache           :        8.7   Number of calls to cache        :       &lt;span style="font-weight: bold;text-decoration:underline"&gt;8542&lt;/span&gt;&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Now, I have enabled ReUse Statement on these steps.  I have not changed anything else.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre   style=";font-family:courier new;font-size:78%;"&gt;                         C o m p i l e    E x e c u t e    F e t c h        Total&lt;br /&gt;SQL Statement                  Count   Time     Count   Time     Count   Time     Time&lt;br /&gt;------------------------------ ------- -------- ------- -------- ------- -------- --------&lt;br /&gt;99XxxXxx.Step02.S                    &lt;span style="font-weight: bold;text-decoration:underline"&gt;1&lt;/span&gt;      0.0    8453    &lt;span style="font-weight: bold;text-decoration:underline"&gt;342.3&lt;/span&gt;       0      0.0    342.3&lt;br /&gt;99XxxXxx.Step03.S                    &lt;span style="font-weight: bold;text-decoration:underline"&gt;1&lt;/span&gt;      0.0    8453     &lt;span style="font-weight: bold;text-decoration:underline"&gt;83.3&lt;/span&gt;       0      0.0     83.3&lt;br /&gt;99XxxXxx.Step05.S                    &lt;span style="font-weight: bold;text-decoration:underline"&gt;1&lt;/span&gt;      0.0    8453      &lt;span style="font-weight: bold;text-decoration:underline"&gt;8.7&lt;/span&gt;       0      0.0      8.7&lt;br /&gt;99XxxXxx.Step06.S                    &lt;span style="font-weight: bold;text-decoration:underline"&gt;1&lt;/span&gt;      0.0    8453      &lt;span style="font-weight: bold;text-decoration:underline"&gt;7.6&lt;/span&gt;       0      0.0      7.6&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;Total run time                :     &lt;span style="font-weight: bold;text-decoration:underline"&gt;5534.1&lt;/span&gt;&lt;br /&gt;Total time in application SQL :     5341.7   Percent time in application SQL :       96.5%&lt;br /&gt;Total time in PeopleCode      :      190.8   Percent time in PeopleCode      :        3.4%&lt;br /&gt;Total time in cache           :        1.1   Number of calls to cache        :         &lt;span style="font-weight: bold;text-decoration:underline"&gt;90&lt;/span&gt;&lt;br /&gt;------------------------------------------------------------------------------------------&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Notice that:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The number of compilations for each step has gone down to 1, though the number of executions remains the same&lt;/li&gt;&lt;li&gt;The execution time for the first three statements has fallen by nearly 90%.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The improvement in the 4th statement is quite modest because it did not contain any bind variables, but clearly some of the time reported as execution time by Application Engine is associated with the preparation of a new SQL statement.&lt;/li&gt;&lt;/ul&gt;To emphasise the point, lets look at the effect on the database.  The following are extracts from the TKPROF output for Oracle SQL trace files for these processes.&lt;br /&gt;&lt;br /&gt;First the TKPROF without ReUse Statement:&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre   style=";font-family:courier new;font-size:78%;"&gt;OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS&lt;br /&gt;&lt;br /&gt;call     count       cpu    elapsed       disk      query    current        rows&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;Parse   101063   2600.60    2602.83       6197     661559          4           0&lt;/span&gt;&lt;br /&gt;Execute 101232   1817.96    3787.17    1572333   73729207   10617830     4770112&lt;br /&gt;Fetch    96186    385.41    1101.47     374425   25986600          0       96285&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;total   298481   4803.97    7491.48    1952955  100377366   10617834     4866397&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;Misses in library cache during parse: 25498&lt;/span&gt;&lt;br /&gt;Misses in library cache during execute: 90&lt;br /&gt;&lt;br /&gt;Elapsed times include waiting on following events:&lt;br /&gt;Event waited on                             Times   Max. Wait  Total Waited&lt;br /&gt;----------------------------------------   Waited  ----------  ------------&lt;br /&gt;db file sequential read                   1199472        0.36       2601.83&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;SQL*Net message from client                130345        1.57        296.50&lt;/span&gt;&lt;br /&gt;db file scattered read                       8816        0.39        171.47&lt;br /&gt;&lt;br /&gt;OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS&lt;br /&gt;&lt;br /&gt;call     count       cpu    elapsed       disk      query    current        rows&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;Parse   100002     13.51      13.57         17        820         94           0&lt;br /&gt;Execute 131495     30.00      31.31       7025      29277      21164       74315&lt;br /&gt;Fetch   141837    218.77     295.49     159969    3039304         12      519406&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;total   373334    262.28     340.38     167011    3069401      21270      593721&lt;span style="font-weight: bold;text-decoration:underline"&gt;&lt;br /&gt;&lt;br /&gt;160446  user  SQL statements in session.&lt;/span&gt;&lt;br /&gt;70478  internal SQL statements in session.&lt;br /&gt;230924  SQL statements in session.&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;And now with ReUse Statement set on only those four steps&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre   style=";font-family:courier new;font-size:78%;"&gt;OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS&lt;br /&gt;&lt;br /&gt;call     count       cpu    elapsed       disk      query    current        rows&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;Parse    67238     10.24      10.75         47       4415          9           0&lt;/span&gt;&lt;br /&gt;Execute 101160   1650.25    4040.88    1766325  129765633   11160830     4781797&lt;br /&gt;Fetch    96123    385.50    1024.50     372737   26097251          0      103844&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;total   264521   2045.99    5076.14    2139109  155867299   11160839     4885641&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;Misses in library cache during parse: 73&lt;/span&gt;&lt;br /&gt;Misses in library cache during execute: 21&lt;br /&gt;&lt;br /&gt;Elapsed times include waiting on following events:&lt;br /&gt;Event waited on                             Times   Max. Wait  Total Waited&lt;br /&gt;----------------------------------------   Waited  ----------  ------------&lt;br /&gt;db file sequential read                   1506834        0.61       2839.19&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;SQL*Net message from client                130312        1.53        258.81&lt;/span&gt;&lt;br /&gt;db file scattered read                       8782        0.37        147.01&lt;br /&gt;&lt;br /&gt;OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS&lt;br /&gt;&lt;br /&gt;call     count       cpu    elapsed       disk      query    current        rows&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;Parse     1331      0.46       0.46          0        173         16           0&lt;br /&gt;Execute   4044      2.72       5.82      12923      33374      24353      113323&lt;br /&gt;Fetch     5697      8.38      13.43      15550      55431         12       13449&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;total    11072     11.56      19.72      28473      88978      24381      126772&lt;br /&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;&lt;br /&gt;67425  user  SQL statements in session.&lt;/span&gt;&lt;br /&gt;3154  internal SQL statements in session.&lt;br /&gt;70579  SQL statements in session.&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Nearly all the saving is in parse time of non-recursive statements, the rest is the reduction of recursive SQL because there is less parsing.&lt;/li&gt;&lt;li&gt;There is less parsing, because there are fewer different SQL statements submitted by Application Engine.  The number of user statements has fallen from 160446 to 67425.&lt;/li&gt;&lt;li&gt;The number of misses on the library cache has fallen from 25498 to just 73.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;There has been a reduction in &lt;span style="font-style: italic;"&gt;SQL*Net message from client&lt;/span&gt; (database idle time) from 296 seconds to 253 because the Application Engine program spends less time compiling SQL statements.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;text-decoration:underline"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Enabling ReUse Statement can have a very significant effect on the performance of Application Engine batches.  It is most effective when SQL statements with &lt;span style="font-style: italic;"&gt;%BIND()&lt;/span&gt; variables are executed within loops.  Otherwise, for each execution of the loop, Application Engine must recompile the SQL statement with different bind variable values, which the database will treat as a new statement that must be parsed.&lt;br /&gt;&lt;br /&gt;SQL parsing is CPU intensive.  Reducing excessive parse also reduces CPU consumption on the database server.  It can also reduce physical I/O to the database catalogue.  On PeopleSoft 8.x applications that use Unicode, &lt;a target="_blank" href="http://www.go-faster.co.uk/bugs.htm#unicode_oddity.pps"&gt;the overhead of parsing is magnified by the use of length checking constraints on all character columns&lt;/a&gt;.  This is &lt;a target="_self" href="http://blog.psftdba.com/2007/07/changes-to-long-columns-and-unicode-in.html"&gt;no longer an issue in version 9 applications which use character semantics&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you use Oracle's Automatic Memory Management, excessive parsing can cause the database to allocate more memory to the Shared Pool at the expense of the Block Buffer Cache.  This in turn can increase physical I/O and can degrade query performance.&lt;br /&gt;&lt;br /&gt;Bind Variables are a good thing.  You should use them.  Therefore, ReUse Statement is also a good thing.  You should use that too!&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-5642770847335457101?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/MkD6FupaJ8s" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/MkD6FupaJ8s/performance-benefits-of-reuse-statement_27.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/02/performance-benefits-of-reuse-statement_27.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-3155164330673361627</guid><pubDate>Thu, 26 Feb 2009 22:48:00 +0000</pubDate><atom:updated>2009-02-27T00:04:21.793Z</atom:updated><category domain="http://www.blogger.com/atom/ns#">Application Engine</category><category domain="http://www.blogger.com/atom/ns#">PeopleSoft Temporary Records</category><title>Do You Need More Temporary Table Instances?</title><description>When an Application Engine loads a program prior to execution, it attempts to allocate an instance of each temporary record specified in the program to itself.  If the allocation of a table fails because there are no available instances, Application Engine is will use the shared instance (unless the program is configured to abort if non-shared tables cannot be assigned).  In this case it will write an entry to the message log to warn that the shared instance of the record has been used.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_SlmmwRbAUdk/SacmNM0f_3I/AAAAAAAAAJg/R1OitFDbcfA/s1600-h/tr_more.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 85px;" src="http://1.bp.blogspot.com/_SlmmwRbAUdk/SacmNM0f_3I/AAAAAAAAAJg/R1OitFDbcfA/s320/tr_more.PNG" alt="" id="BLOGGER_PHOTO_ID_5307252694101000050" border="0"&gt;&lt;/a&gt;When processes use the shared tables performance is likely to be degraded by contention on the table.  The &lt;span style="font-style: italic;"&gt;%TruncateTable()&lt;/span&gt; PeopleCode macro generates a &lt;span style="font-style: italic;"&gt;DELETE&lt;/span&gt; by process instance on the shared table instead of a &lt;span style="font-style: italic;"&gt;TRUNCATE &lt;/span&gt;command.&lt;br /&gt;&lt;br /&gt;The problem is that unless you look in the message log, you will not know that this is happening.  However, it easy to write a query that will look at the message log table and report whenever this has occurred.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#tr_moreinst.sql"&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;select  p.message_parm recname, r.prcsname&lt;br /&gt;,  count(*) occurances&lt;br /&gt;,  max(l.dttm_stamp_sec) last_occurance&lt;br /&gt;,  max(p.process_instance) process_instance&lt;br /&gt;from  ps_message_log l&lt;br /&gt;,  ps_message_logparm p&lt;br /&gt; left outer join psprcsrqst r&lt;br /&gt; on r.prcsinstance = p.process_instance&lt;br /&gt;where  l.message_set_nbr = 108&lt;br /&gt;and    l.message_nbr = 544&lt;br /&gt;and    p.process_instance = l.process_instance&lt;br /&gt;and    p.message_seq = l.message_seq&lt;br /&gt;and    l.dttm_stamp_sec &gt;= sysdate - 7&lt;br /&gt;group by p.message_parm, r.prcsname&lt;br /&gt;order by 1,2&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;This report tells you which programs failed to allocated instances of which record, how many times that has happened within the last 7 days.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 0px solid rgb(0, 0, 0); overflow: auto; width: 100%; padding-left: 4px; padding-right: 4px; background-color: rgb(238, 238, 238);"&gt;&lt;pre style="font-family: courier new; font-size: 85%;"&gt;            Processes Unable to Allocate Non-Shared Temporary Record&lt;br /&gt;&lt;br /&gt;                                                                  Last&lt;br /&gt;Record          Process                  Last                   Process&lt;br /&gt;Name            Name         Occurrences Occurrence            Instance&lt;br /&gt;--------------- ------------ ----------- ------------------- ----------&lt;br /&gt;TL_ABS_WRK      TL_TIMEADMIN           4 08:24:39 01/01/2009      12345&lt;br /&gt;TL_ATTND_HST1   TL_TIMEADMIN          10 08:23:40 01/01/2009      12345&lt;br /&gt;TL_COMP_BAL     TL_TIMEADMIN          11 08:23:40 01/01/2009      12345&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;NB: Just because an Application Engine could not allocate a non-shared table, does not automatically imply that you need more instances of that record.  It could be that other processes had failed, but the temporary tables are still allocated to the process until the process is either restarted and completes successfully, or the process is deleted or cancelled.&lt;br /&gt;&lt;br /&gt;You might choose to create some &lt;span style="font-style: italic;"&gt;spare &lt;/span&gt;instances of records to allow for failed processes, but if you do not clear failed processes you will eventually run out of instances.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-3155164330673361627?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/MUSdBrUZvGc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/MUSdBrUZvGc/do-you-need-more-temporary-table.html</link><author>info@go-faster.co.uk (David Kurtz)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_SlmmwRbAUdk/SacmNM0f_3I/AAAAAAAAAJg/R1OitFDbcfA/s72-c/tr_more.PNG" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/02/do-you-need-more-temporary-table.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-25740336.post-975425790198258754</guid><pubDate>Wed, 11 Feb 2009 23:22:00 +0000</pubDate><atom:updated>2009-02-16T15:58:33.931Z</atom:updated><title>UKOUG PeopleSoft Conference 2009 - Call for Papers</title><description>Building on the success of the inaugural UKOUG PeopleSoft Conference &amp; Exhibition in 2008, this Conference, presented by &lt;a target="_blank" href="http://www.oug.org/"&gt;UKOUG&lt;/a&gt; and GPUG, will provide a forum for the presentation and exchange of ideas and practical experiences within the areas of PeopleSoft Financials, HCM/HR and Technology. The multi-stream agenda will feature keynote presentations, technical and non-technical sessions, roundtables, panel discussions and more. &lt;br /&gt;If you are interested in sharing your experience of using PeopleSoft technology and applications, here is your chance as the call for papers is now open. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Deadlines are tight. &lt;/b&gt;&amp;nbsp;Submit your abstracts now at: &lt;a target="_blank" href="http://www.oug.org/peoplesoft"&gt;www.oug.org/peoplesoft&lt;/a&gt;   &lt;br /&gt;&lt;br /&gt;Closing date for submissions:  &lt;span style="font-weight:bold;"&gt;Friday 27th February&lt;/span&gt;.  &lt;br /&gt;&lt;br /&gt;The review panel, comprised of PeopleSoft community members, will evaluate all abstracts submitted by the closing date. The authors of accepted abstracts will receive confirmation at the beginning of March.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://www.go-faster.co.uk/"&gt;©David Kurtz, Go-Faster Consultancy Ltd.&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25740336-975425790198258754?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ThePeoplesoftDbaBlog/~4/GRS0qE1XT_U" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/ThePeoplesoftDbaBlog/~3/GRS0qE1XT_U/ukoug-conference-series-peoplesoft-2009.html</link><author>info@go-faster.co.uk (David Kurtz)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.psftdba.com/2009/02/ukoug-conference-series-peoplesoft-2009.html</feedburner:origLink></item></channel></rss>
