<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-25740336</id><updated>2009-11-29T19:03:53.461Z</updated><title type='text'>The PeopleSoft DBA Blog</title><subtitle type='html'>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;.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.psftdba.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default?start-index=26&amp;max-results=25'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>73</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-25740336.post-400004847550273152</id><published>2009-11-25T08:23:00.002Z</published><updated>2009-11-25T13:15:45.866Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='COBOL'/><title type='text'>Controlling How PeopleSoft Cobol Collects Statistics</title><content type='html'>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 (http://blog.go-faster.co.uk/2009/10/global-temporary-tables-shared.html) 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&lt;br /&gt; Action Type     : SQL UPDATE&lt;br /&gt; In Pgm Section  : SQLRT: EXECUTE-STMT                                 &lt;br /&gt; With Return Code: 38029 &lt;br /&gt; Error Message   : ORA-38029: object statistics are locked&lt;br /&gt; Stored Stmt     : GPPSERVC_U_STATS  &lt;br /&gt; 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&lt;br /&gt;%UPDATESTATS(PS_GP_PYE_STAT_WRK)&lt;br /&gt;;&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 target="_blank" href="http://www.go-faster.co.uk/scripts/wrapper848meta.sql"&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&lt;br /&gt;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 built a data mover script to replace them with calls to my replacement package with the following SQL.&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&lt;br /&gt;spool updatestats_after.dms&lt;br /&gt;select 'STORE '||pgm_name||'_'||stmt_type||'_'||stmt_name&lt;br /&gt;||CHR(10)&lt;br /&gt;||'BEGIN wrapper.ps_stats(p_ownname=&amp;gt;user,p_tabname=&amp;gt;'''&lt;br /&gt;||substr(stmt_text&lt;br /&gt; , INSTR(stmt_text,'(')+1&lt;br /&gt; , INSTR(stmt_text,')')-INSTR(stmt_text,'(')-1&lt;br /&gt; )&lt;br /&gt;||'''); END;;'&lt;br /&gt;from ps_sqlstmt_tbl&lt;br /&gt;where stmt_text like '%UPDATESTATS(%'&lt;br /&gt;/&lt;br /&gt;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, you can 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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/400004847550273152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=400004847550273152&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/400004847550273152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/400004847550273152'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/11/controlling-how-peoplesoft-cobol.html' title='Controlling How PeopleSoft Cobol Collects Statistics'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-2021058070571426795</id><published>2009-10-28T08:19:00.000Z</published><updated>2009-10-28T08:19:28.430Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Database Links'/><title type='text'>Database Links and PeopleSoft</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/2021058070571426795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=2021058070571426795&amp;isPopup=true' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/2021058070571426795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/2021058070571426795'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/10/database-links-and-peoplesoft.html' title='Database Links and PeopleSoft'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-310734979297341651</id><published>2009-10-11T17:55:00.000+01:00</published><updated>2009-10-11T17:55:10.406+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Batch Timings'/><title type='text'>Aggregating &amp; Purging Batch Timings</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/310734979297341651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=310734979297341651&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/310734979297341651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/310734979297341651'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/10/aggregating-purging-batch-timings.html' title='Aggregating &amp; Purging Batch Timings'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-8773421305452583790</id><published>2009-09-10T19:40:00.015+01:00</published><updated>2009-09-11T14:20:00.643+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><title type='text'>Identifying Application Engine Source Code</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/8773421305452583790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=8773421305452583790&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8773421305452583790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8773421305452583790'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/09/identifying-source-code.html' title='Identifying Application Engine Source Code'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></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'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-1358044497525697450</id><published>2009-07-28T06:39:00.008+01:00</published><updated>2009-07-28T07:25:47.865+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Truncate'/><category scheme='http://www.blogger.com/atom/ns#' term='Freelist'/><category scheme='http://www.blogger.com/atom/ns#' term='ASSM'/><title type='text'>Automatic Segment Space -v- Freelist Management for PeopleSoft Temporary Records</title><content type='html'>&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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/1358044497525697450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=1358044497525697450&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/1358044497525697450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/1358044497525697450'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/07/automatic-segment-space-v-freelist.html' title='Automatic Segment Space -v- Freelist Management for PeopleSoft Temporary Records'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-5691892938693685558</id><published>2009-07-23T19:41:00.006+01:00</published><updated>2009-09-22T21:36:27.226+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Recyclebin'/><title type='text'>PeopleSoft and the Oracle Recycle Bin</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/5691892938693685558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=5691892938693685558&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5691892938693685558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5691892938693685558'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/07/peoplesoft-and-oracle-recycle-bin.html' title='PeopleSoft and the Oracle Recycle Bin'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-3231799605698304596</id><published>2009-07-14T10:18:00.006+01:00</published><updated>2009-07-14T11:59:59.218+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Terminated Connection Timeout'/><category scheme='http://www.blogger.com/atom/ns#' term='Dead Connect Detection'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL*Net'/><title type='text'>Oracle Terminated Connection Timeout</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/3231799605698304596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=3231799605698304596&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/3231799605698304596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/3231799605698304596'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/07/oracle-terminated-connection-timeout.html' title='Oracle Terminated Connection Timeout'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-6355404204789194109</id><published>2009-07-06T22:48:00.010+01:00</published><updated>2009-09-22T22:05:40.656+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='global temporary tables'/><category scheme='http://www.blogger.com/atom/ns#' term='Restartability'/><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><title type='text'>Dynamically Switching PeopleSoft Temporary Records between Global Temporary and Normal Tables during Application Engine Programs</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/6355404204789194109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=6355404204789194109&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/6355404204789194109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/6355404204789194109'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/07/dynamically-switching-peoplesoft.html' title='Dynamically Switching PeopleSoft Temporary Records between Global Temporary and Normal Tables during Application Engine Programs'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></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></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-1282014570530371387</id><published>2009-06-25T20:30:00.005+01:00</published><updated>2009-07-16T11:41:50.096+01:00</updated><title type='text'>Controlling  How %UpdateStats Collects Optimizer Statistics</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/1282014570530371387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=1282014570530371387&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/1282014570530371387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/1282014570530371387'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/06/controlling-how-updatestats-collects.html' title='Controlling  How %UpdateStats Collects Optimizer Statistics'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-8339463468628673959</id><published>2009-06-25T20:23:00.007+01:00</published><updated>2009-06-30T13:30:26.553+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Oracle 10g'/><category scheme='http://www.blogger.com/atom/ns#' term='Statistics Retention'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimizer Dynamic Sampling'/><title type='text'>Oracle 10g Statistics History Retention in PeopleSoft</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/8339463468628673959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=8339463468628673959&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8339463468628673959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8339463468628673959'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/06/oracle-10g-statistics-history-retention.html' title='Oracle 10g Statistics History Retention in PeopleSoft'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-410767148542670863</id><published>2009-05-19T11:30:00.009+01:00</published><updated>2009-05-29T09:51:05.193+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PeopleTools 8.1x'/><category scheme='http://www.blogger.com/atom/ns#' term='Tuxedo'/><title type='text'>Manually Booting Tuxedo Application Server Processes in Parallel</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/410767148542670863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=410767148542670863&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/410767148542670863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/410767148542670863'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/05/manually-booting-tuxedo-application.html' title='Manually Booting Tuxedo Application Server Processes in Parallel'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-5585053716472368597</id><published>2009-05-13T07:00:00.006+01:00</published><updated>2009-05-21T23:17:46.499+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Tuning'/><category scheme='http://www.blogger.com/atom/ns#' term='Performance Monitor'/><category scheme='http://www.blogger.com/atom/ns#' term='Conference'/><category scheme='http://www.blogger.com/atom/ns#' term='PeopleSoft Temporary Records'/><title type='text'>UKOUG PeopleSoft Conference 2009 Presentations</title><content type='html'>&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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/5585053716472368597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=5585053716472368597&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5585053716472368597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5585053716472368597'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/05/ukoug-peoplesoft-conference-2009.html' title='UKOUG PeopleSoft Conference 2009 Presentations'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-3451465819945962958</id><published>2009-04-22T09:08:00.013+01:00</published><updated>2009-09-22T21:49:13.833+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='Temporary Records'/><title type='text'>Reducing Unnecessary Instances of Temporary Records</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/3451465819945962958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=3451465819945962958&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/3451465819945962958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/3451465819945962958'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/04/reducing-unnecessary-instances-of.html' title='Reducing Unnecessary Instances of Temporary Records'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-4729814106209241431</id><published>2009-04-06T15:23:00.005+01:00</published><updated>2009-04-08T19:12:34.326+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DBMS_STATS'/><category scheme='http://www.blogger.com/atom/ns#' term='Partitions'/><title type='text'>Statistics Management for Partitioned Objects in PeopleSoft</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/4729814106209241431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=4729814106209241431&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/4729814106209241431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/4729814106209241431'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/04/statistics-management-for-partitioned.html' title='Statistics Management for Partitioned Objects in PeopleSoft'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-5488747950482938823</id><published>2009-04-06T14:39:00.009+01:00</published><updated>2009-04-07T08:29:04.957+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DBMS_STATS'/><category scheme='http://www.blogger.com/atom/ns#' term='PeopleSoft Temporary Records'/><title type='text'>Statistics Management for PeopleSoft Temporary Records in Application Engine Programs</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/5488747950482938823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=5488747950482938823&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5488747950482938823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5488747950482938823'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/04/statistics-management-for-peoplesoft.html' title='Statistics Management for PeopleSoft Temporary Records in Application Engine Programs'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-4825816197248189548</id><published>2009-04-02T20:19:00.003+01:00</published><updated>2009-04-02T20:28:41.214+01:00</updated><title type='text'>Automatically Granting Privileges on Newly Created Tables (continued)</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/4825816197248189548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=4825816197248189548&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/4825816197248189548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/4825816197248189548'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/04/automatically-granting-privileges-on.html' title='Automatically Granting Privileges on Newly Created Tables (continued)'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-9028954932483240940</id><published>2009-03-13T11:17:00.020Z</published><updated>2009-09-22T21:57:07.473+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Oracle Enterprise Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Grid Control'/><category scheme='http://www.blogger.com/atom/ns#' term='DBMS_APPLICATION_INFO'/><title type='text'>Using Oracle Enterprise Manager (Grid Control) with PeopleSoft</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/9028954932483240940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=9028954932483240940&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/9028954932483240940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/9028954932483240940'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/03/using-oracle-enterprise-manager-grid.html' title='Using Oracle Enterprise Manager (Grid Control) with PeopleSoft'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-8681325713263750232</id><published>2009-03-12T19:41:00.001Z</published><updated>2009-03-16T17:06:53.266Z</updated><title type='text'>Minimum Number of Application Server Processes</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/8681325713263750232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=8681325713263750232&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8681325713263750232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8681325713263750232'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/03/minimum-number-of-application-server.html' title='Minimum Number of Application Server Processes'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-8017166761966953714</id><published>2009-03-05T19:28:00.009Z</published><updated>2009-04-02T20:34:07.906+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Privileges'/><category scheme='http://www.blogger.com/atom/ns#' term='DDL trigger'/><title type='text'>Automatically Granting Privileges on Newly Created Tables</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/8017166761966953714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=8017166761966953714&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8017166761966953714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/8017166761966953714'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/03/automatically-granting-privileges-on.html' title='Automatically Granting Privileges on Newly Created Tables'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-5642770847335457101</id><published>2009-02-27T16:01:00.008Z</published><updated>2009-03-03T09:27:25.460Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Parse'/><category scheme='http://www.blogger.com/atom/ns#' term='ReUse Statement'/><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><title type='text'>Performance Benefits of ReUse Statement Flag in Application Engine</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/5642770847335457101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=5642770847335457101&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5642770847335457101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/5642770847335457101'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/02/performance-benefits-of-reuse-statement_27.html' title='Performance Benefits of ReUse Statement Flag in Application Engine'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-3155164330673361627</id><published>2009-02-26T22:48:00.006Z</published><updated>2009-02-27T00:04:21.793Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='PeopleSoft Temporary Records'/><title type='text'>Do You Need More Temporary Table Instances?</title><content type='html'>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;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/3155164330673361627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=3155164330673361627&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/3155164330673361627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/3155164330673361627'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/02/do-you-need-more-temporary-table.html' title='Do You Need More Temporary Table Instances?'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></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></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-975425790198258754</id><published>2009-02-11T23:22:00.004Z</published><updated>2009-02-16T15:58:33.931Z</updated><title type='text'>UKOUG PeopleSoft Conference 2009 - Call for Papers</title><content type='html'>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;</content><link rel='related' href='http://www.oug.org/peoplesoft' title='UKOUG PeopleSoft Conference 2009 - Call for Papers'/><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/975425790198258754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=975425790198258754&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/975425790198258754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/975425790198258754'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/02/ukoug-conference-series-peoplesoft-2009.html' title='UKOUG PeopleSoft Conference 2009 - Call for Papers'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-7405043168070076477</id><published>2009-01-30T12:18:00.022Z</published><updated>2009-02-16T17:01:06.281Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='PeopleSoft Temporary Records'/><title type='text'>Managing Changes to the Number of Instances of Temporary Tables used in Application Engine Programs</title><content type='html'>When you run multiple copies of either the same Application Engine program, or different Application Engines that happen to use the same temporary work records, you need to worry about how many instances of the program or programs are likely to run concurrently, and hence how many instances of the temporary table to build.&lt;br /&gt;&lt;br /&gt;But how do you manage these tables when you change the number of instances in the Application Engine properties?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:120%;" &gt;How many tables are built for each Temporary Record?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The number of instances of each Application Engine program is set in the properties for that program (and stored on the PeopleTools table PSAEAPPLDEFN in the column TEMPTBLINSTANCES).&lt;br /&gt;&lt;br /&gt;This screenshot is the Application Engine Program Properties for TL_TIMEADMIN.  It is delivered configured for up to 10 concurrent instances.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_SlmmwRbAUdk/SYLxTemmEVI/AAAAAAAAAIw/p9QWLHSM87g/s1600-h/aeprop.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 270px; height: 320px;" src="http://4.bp.blogspot.com/_SlmmwRbAUdk/SYLxTemmEVI/AAAAAAAAAIw/p9QWLHSM87g/s320/aeprop.png" alt="" id="BLOGGER_PHOTO_ID_5297061428675875154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The number of tables that are built for each Temporary Record is the sum of the instances in all the Application Engine programs in which the record is used, plus the number of Global Instances (in set up on the PeopleTools Options page.&lt;br /&gt;&lt;br /&gt;Let’s take the record TL_PROF_LIST as an example.  It is defined as a Temporary Record in 8 different Application Engine programs (in my HCM8.9 demo system).&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.temptblinstances&lt;br /&gt;FROM   psaeappltemptbl a, psaeappldefn b&lt;br /&gt;WHERE  a.ae_applid = b.ae_applid&lt;br /&gt;AND    a.recname = 'TL_PROF_LIST'&lt;br /&gt;ORDER BY a.recname&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;RECNAME         AE_APPLID    TEMPTBLINSTANCES&lt;br /&gt;--------------- ------------ ----------------&lt;br /&gt;TL_PROF_LIST    TL_AGG_SECTN                1&lt;br /&gt;TL_PROF_LIST    TL_OUTTCD                   5&lt;br /&gt;TL_PROF_LIST    TL_PUB_TM1                  5&lt;br /&gt;TL_PROF_LIST    TL_SCHHRSRPT                5&lt;br /&gt;TL_PROF_LIST    TL_SCHRES_AE                9&lt;br /&gt;TL_PROF_LIST    TL_ST_LIB                   5&lt;br /&gt;TL_PROF_LIST    TL_TIMEADMIN               10&lt;br /&gt;TL_PROF_LIST    TL_TRPROFILE               10&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;So, across all the programs 50 temporary tables are required.&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 * FROM pstemptblcntvw &lt;br /&gt;WHERE  recname = 'TL_PROF_LIST'&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;RECNAME         TEMPTBLINSTANCES&lt;br /&gt;--------------- ----------------&lt;br /&gt;TL_PROF_LIST                  50&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The system has three global 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;SELECT temptblinstances&lt;br /&gt;FROM   psoptions&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;TEMPTBLINSTANCES&lt;br /&gt;----------------&lt;br /&gt;               3&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;So, Application Designer will build 54 tables based on this record.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;3 ‘global’ instances for Application Engines without a Process Instance number.  The table names will be suffixed with numbers 1 to 3.&lt;/li&gt;&lt;li&gt;50 ‘private’ instances for the number of requested instances of the Application Engines.  The table names will be suffixed with numbers 4 to 53&lt;/li&gt;&lt;li&gt;1 ‘shared’ version without a suffix (in other words the usual name) which is used if there is no instance no already allocated to a process instance.&lt;/li&gt;&lt;/ul&gt;And this is the top and bottom of the script to build the tables only generated by Application Designer.&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;CREATE TABLE PS_TL_PROF_LIST (PROCESS_INSTANCE DECIMAL(10) NOT NULL,&lt;br /&gt;EMPLID VARCHAR2(11) NOT NULL,&lt;br /&gt;EMPL_RCD SMALLINT NOT NULL,&lt;br /&gt;START_DT DATE,&lt;br /&gt;END_DT DATE) TABLESPACE TLWORK STORAGE (INITIAL 40000 NEXT 100000&lt;br /&gt;MAXEXTENTS UNLIMITED PCTINCREASE 0) PCTFREE 10 PCTUSED 80&lt;br /&gt;/&lt;br /&gt;…&lt;br /&gt;CREATE TABLE PS_TL_PROF_LIST53 (PROCESS_INSTANCE DECIMAL(10) NOT NULL,&lt;br /&gt;EMPLID VARCHAR2(11) NOT NULL,&lt;br /&gt;EMPL_RCD SMALLINT NOT NULL,&lt;br /&gt;START_DT DATE,&lt;br /&gt;END_DT DATE) TABLESPACE TLWORK STORAGE (INITIAL 40000 NEXT 100000&lt;br /&gt;MAXEXTENTS UNLIMITED PCTINCREASE 0) PCTFREE 10 PCTUSED 80&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:120%;" &gt;Are there any temporary tables that have not been built but that should be built?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you increase the number of instances of temporary tables on an Application Engine program then you may need to build the extra temporary tables.  This query reports the missing tables.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#temptblinstances.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;SELECT r.recname&lt;br /&gt;,      n.n instance&lt;br /&gt;,      c.temptblinstances&lt;br /&gt;     + o.temptblinstances temptblinstances&lt;br /&gt;FROM   pstemptblcntvw c&lt;br /&gt;,      psrecdefn r&lt;br /&gt;,      (SELECT rownum-1 n FROM psrecdefn&lt;br /&gt;        WHERE rownum &lt;= 100) n&lt;br /&gt;,      psoptions o&lt;br /&gt;WHERE  r.recname = c.recname&lt;br /&gt;AND    n.n &lt;= c.temptblinstances+o.temptblinstances&lt;br /&gt;AND NOT EXISTS(&lt;br /&gt;       SELECT 'x'&lt;br /&gt;       FROM   user_tables t&lt;br /&gt;       WHERE  t.table_name = &lt;br /&gt;            DECODE(r.sqltablename, ' ', 'PS_'||r.recname,&lt;br /&gt;                   r.sqltablename) ||DECODE(n.n,0,'',n.n)&lt;br /&gt;        )&lt;br /&gt;ORDER BY 1,2&lt;br /&gt;/&lt;/pre&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;I dropped PS_TL_PROF_LIST42, but I also increased the number of instance of TL_TIMEADMIN from 10 to 11.  So the query reports that instances 42 and 54 of this table are missing, and all the other temporary tables for TL_TIMEADMIN also report a missing instance.&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;RECNAME           INSTANCE TEMPTBLINSTANCES&lt;br /&gt;--------------- ---------- ----------------&lt;br /&gt;…&lt;br /&gt;TL_PMTCH_TMP1           19               19&lt;br /&gt;TL_PMTCH_TMP2           19               19&lt;br /&gt;TL_PROF_LIST            42               54&lt;br /&gt;TL_PROF_LIST            54               54&lt;br /&gt;TL_PROF_WRK             38               38&lt;br /&gt;TL_PT_FINAL             29               29&lt;br /&gt;…&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The remedy is very simple.  Application Designer will build a script for just the missing tables.&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;CREATE TABLE PS_TL_PROF_LIST42 (PROCESS_INSTANCE DECIMAL(10) NOT NULL,&lt;br /&gt;EMPLID VARCHAR2(11) NOT NULL,&lt;br /&gt;EMPL_RCD SMALLINT NOT NULL,&lt;br /&gt;START_DT DATE,&lt;br /&gt;END_DT DATE) TABLESPACE TLWORK STORAGE (INITIAL 40000 NEXT 100000&lt;br /&gt;MAXEXTENTS UNLIMITED PCTINCREASE 0) PCTFREE 10 PCTUSED 80&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:120%;" &gt;Are there any temporary tables built that should not be built?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you have reduced the number of temporary tables, then you may need to drop the excess tables.&lt;br /&gt;&lt;br /&gt;This query reports tables that are beyond the number required.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#temptblinstances.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;SELECT r.recname&lt;br /&gt;,      n.n instance&lt;br /&gt;,      c.temptblinstances&lt;br /&gt;     + o.temptblinstances temptblinstances&lt;br /&gt;,      t.table_name&lt;br /&gt;FROM   pstemptblcntvw c&lt;br /&gt;,      psrecdefn r&lt;br /&gt;,      (SELECT rownum-1 n FROM psrecfield&lt;br /&gt;        WHERE rownum &lt;= 100&lt;br /&gt;       ) n&lt;br /&gt;,      user_tables t&lt;br /&gt;,      psoptions o&lt;br /&gt;WHERE  r.recname = c.recname&lt;br /&gt;AND    t.table_name = &lt;br /&gt;          DECODE(r.sqltablename, ' ', 'PS_'||r.recname,&lt;br /&gt;                 r.sqltablename) ||DECODE(n.n,0,'',n.n)&lt;br /&gt;AND    n.n &gt; c.temptblinstances+o.temptblinstances&lt;br /&gt;ORDER BY r.recname, n.n&lt;br /&gt;/&lt;/pre&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I built the missing tables for the previous example, but then I reduced the number of instances on TL_TIMEADMIN back to 10.  Now, the query reports that there is an extra table for each record beyond the number defined.&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;RECNAME         INSTANCE TEMPTBLINSTANCES TABLE_NAME&lt;br /&gt;------------- -------- ---------------- ------------------&lt;br /&gt;…&lt;br /&gt;TL_PMTCH_TMP1       19               18 PS_TL_PMTCH_TMP119&lt;br /&gt;TL_PMTCH_TMP2       19               18 PS_TL_PMTCH_TMP219&lt;br /&gt;TL_PROF_LIST        54               53 PS_TL_PROF_LIST54&lt;br /&gt;TL_PROF_WRK         38               37 PS_TL_PROF_WRK38&lt;br /&gt;TL_PT_FINAL         29               28 PS_TL_PT_FINAL29&lt;br /&gt;…&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The problem is that Application Designer will not generate the DDL to drop any of these tables.  If you reduce the number of temporary table instances, you will have to drop these tables yourself.  However, now, it is easy to adjust the above query to produce the DDL to drop the tables.&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 'DROP TABLE '||t.table_name||' PURGE;' cmd&lt;br /&gt;FROM   …&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The query then produces these commands.&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;…&lt;br /&gt;DROP TABLE PS_TL_PMTCH_TMP119 PURGE;&lt;br /&gt;DROP TABLE PS_TL_PMTCH_TMP219 PURGE;&lt;br /&gt;DROP TABLE PS_TL_PROF_LIST54 PURGE;&lt;br /&gt;DROP TABLE PS_TL_PROF_WRK38 PURGE;&lt;br /&gt;DROP TABLE PS_TL_PT_FINAL29 PURGE;&lt;br /&gt;…&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#temptblinstances.sql"&gt;The scripts in this posting can be downloaded from my website.&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-7405043168070076477?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/7405043168070076477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=7405043168070076477&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/7405043168070076477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/7405043168070076477'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/01/managing-changes-to-number-of-instances.html' title='Managing Changes to the Number of Instances of Temporary Tables used in Application Engine Programs'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_SlmmwRbAUdk/SYLxTemmEVI/AAAAAAAAAIw/p9QWLHSM87g/s72-c/aeprop.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-7987170379477136396</id><published>2009-01-26T09:24:00.009Z</published><updated>2009-07-04T18:14:50.941+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Truncate'/><category scheme='http://www.blogger.com/atom/ns#' term='row cache lock'/><category scheme='http://www.blogger.com/atom/ns#' term='enq: RO - fast object reuse'/><category scheme='http://www.blogger.com/atom/ns#' term='local write wait'/><category scheme='http://www.blogger.com/atom/ns#' term='Application Engine'/><title type='text'>Factors Affecting Performance of Concurrent Truncate of Working Storage Tables</title><content type='html'>&lt;span style="font-style: italic;"&gt;A longer version of this posting, with detailed experimental results, is &lt;a target="_blank" href="http://www.go-faster.co.uk/docs.htm#local_write_wait"&gt;available on my website&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Over the past year, I have seen problems with Local Write Wait in the Oracle database on two different Oracle systems.  One occasion was in a PeopleSoft Time and Labour batch process, the other was in a custom PL/SQL process in non-PeopleSoft system.&lt;br /&gt;&lt;br /&gt;In both cases, normal tables in the databases were being used for temporary working storage before that data was then written to another table.  The content of the working storage tables was then cleared out by periodically truncating them.  In order to increase overall batch throughput, several instances of the program were run in parallel.  The resulting concurrent truncate operations contended with each other, and the processes did not scale well.&lt;br /&gt;&lt;br /&gt;I have &lt;a target="_blank" href="http://blog.psftdba.com/2008/01/global-temporary-tables-and-peoplesoft.html"&gt;written about this subject previously&lt;/a&gt;.  These problems have prompted me to do some research and testing, I am now able to make definite recommendations.&lt;br /&gt;&lt;br /&gt;Oracle Note &lt;a href="https://metalink.oracle.com/metalink/plsql/f?p=130:14:6390167500306343813::::p14_database_id,p14_docid,p14_show_header,p14_show_help,p14_black_frame,p14_font:NOT,334822.1,1,1,1,helvetica"&gt;334822.1&lt;/a&gt; (which I have also quoted before) provides a good technical description of the database’s internal behaviour. Put simply; truncate (and drop) operations serialise.  Only one process can truncate at any one time.  If you have multiple concurrent processes all trying to truncate their own working storage tables, you could experience performance problems.  Such processes not scale well as the number of concurrent processes increases.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Real Problems&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the case of the non-PeopleSoft PL/SQL process, I was able to recreate the working storage tables as Global Temporary Tables (GTTs) that deleted the rows on commit because the process committed only when each transaction was complete.  Local write wait totally disappeared in this case.  Temporary objects do not need to be recovered, so this mechanism does not apply to them.&lt;br /&gt;&lt;br /&gt;The PeopleSoft scenario involved one of the ‘Time &amp;amp; Labor’ batch processes, TL_TIMEADMIN.  However, GTTs cannot easily be introduced into the T&amp;amp;L batches because there are ‘restartable’.  Therefore, the contents of temporary working storage tables need to be preserved after the process and its session terminates.  This precludes the use of GTTs.&lt;br /&gt;&lt;br /&gt;The combination of &lt;span style="font-style: italic;"&gt;Local Write Wait&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;enq: RO - fast object reuse&lt;/span&gt; accounted for 31% of the total response time.  This is a significant proportion of the total response time.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;local write wait&lt;/span&gt; occurs, as the name suggests, when the session is waiting for its own write operations.  The RO enqueue is used to protect the buffer cache chain while it is scanned for dirty blocks in an object for the database writer to then write to the data files.  &lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;enq: RO - fast object reuse&lt;/span&gt; occurs when a process waits to acquire the RO enqueue, in other words, while somebody else is truncating or dropping an object.&lt;/li&gt;&lt;/ul&gt;Two factors affect the time for which the RO enqueue is held:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The time taken to write the blocks to disk.  Processes that are frequently truncating temporary working storage are also doing a lot of DML operations to populate the working storage and other tables.  The disks under the data files are going to be busy.  If the disk becomes a bottleneck, the duration of the local write wait will certainly increase.&lt;/li&gt;&lt;li&gt;The time taken to scan the buffer cache for dirty blocks to be written to disk and flushed from cache.  The larger the buffer cache, the longer it will take to find these blocks.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;The Metalink note also suggests using a different block size, saying that "a separate buffer pool for temporary tables will also reduce RO enqueue".  It is not clear whether it is more important to have a different block size or a separate buffer pool.  I wanted to find out which factor was more important.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Tests&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I created a simple test to model the behaviour of T&amp;amp;L.  I created pairs of simple tables, populated one of each pair, and then repeatedly copied the data back and forth between them, truncating the source after the copy.   The test script has evolved into a PL/SQL package procedure, mainly so that the tests could be submitted to and run concurrently by the Oracle job scheduler.  There are also procedures to create, populate, and drop the pairs of working storage tables.  The scripts can be &lt;a target="_blank" href="http://www.go-faster.co.uk/scripts.htm#lwr"&gt;downloaded from my website&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I was able to run the same controlled test in a variety of scenarios. I have run the tests on Oracle 10.2.0.3 on various platforms with similar results.  A detailed set of results are available in the &lt;a target="_blank" href="http://www.go-faster.co.uk/docs.htm#local_write_wait"&gt;longer version of this document on my website&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;General Recommendations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you have to store temporarily working data in a database table, it is much better to use a Global Temporary Table, although the design of the application may preclude this.  It is not possible to do this with data used by restartable Application Engine processes, because the contents of the GTT would be lost when the process terminates.&lt;br /&gt;&lt;br /&gt;The Metalink note references unpublished bug 414780 in which a PeopleSoft customer reported this problem, but “they seemed to fix it by changing some PeopleSoft code to implement delete rather than truncate on small temporary tables”.  However, my tests show that this probably degraded performance further.  The individual delete statements take longer than the truncate operations, and the overall test times increased.  Although the truncate operations serialise on the RO enqueue and wait for local writes, this is still better than deleting the data and waiting for the undo information to be written to the redo log.  Furthermore, although the truncate operations did not scale well, the delete operations exhibited negative scalability for the same volumes and concurrency.  They became bottlenecked on redo log.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Using a recycle pool of the same block size as the rest of the database was not effective; possibly because these pools use the same LRU latches.&lt;/li&gt;&lt;li&gt;Using a larger non-default block size improved performance of truncate.  The performance with 32Kb blocks was better than with 16Kb.&lt;/li&gt;&lt;li&gt;Using a larger uniform extent size also improved performance for just the truncate operations and the test as a whole.  Fewer, larger extents were involved, and hence less time was spent on CPU and &lt;span style="font-style: italic;"&gt;row cache lock&lt;/span&gt;.  The overall throughput truncate operations degraded as the number of processes increased, although, the throughput of the test as whole did scale.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The presence or absence of indexes did not have a significant effect on the relative test timings, and does not alter my advice.&lt;/li&gt;&lt;li&gt;The effect of truncating with the REUSE STORAGE option is less clear cut.  There are no waits on row cache lock because the blocks do not have to be cleared out of the buffer cache, but on the other hand more time is spent on local write wait because all the dirty blocks have to be written to disk, hence the RO enqueue is held for longer and more time is spent on enq: RO - fast object reuse.  If you are using an AUTOALLOCATE tablespace then you would be better to use REUSE STORAGE option, but generally you would be slightly better to use a larger uniform extent size and not to use the REUSE STORAGE option.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;PeopleSoft Recommendations&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Over time, PeopleSoft batch processing has moved slightly away from SQR and COBOL.  These types of process cannot be restarted, and so tables used for temporary working storage within the process can usually be recreated as Global Temporary Tables.  This will produce better performance and scalability that any option that involves retaining the permanent table.&lt;br /&gt;&lt;br /&gt;However, we are seeing more processing in PeopleSoft applications done with Application Engine.  If restart has been disabled for an Application Engine program, then temporary records can also be rebuilt as Global Temporary Tables, because their contents does not need to be preserved for another session to pick up.&lt;br /&gt;&lt;br /&gt;Otherwise, move the temporary records and their indexes to tablespace with a 32Kb block size.  The change of assigned tablespace can be managed within Application Designer, and released like any other patch or customisation.  A 32Kb buffer cache must be created in the database instance.  Sizing this is going to be a trade-off between how much memory can be taken from other activities to cache just working storage tables, and how much physical I/O you are going to have to wait for.  Oracle’s Automatic Shared Memory Management is of no assistance here (until Oracle 11g), the KEEP, RECYCLE, and other block size buffer caches must be sized manually (see Oracle Reference Manual for &lt;a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/initparams193.htm#I1010256"&gt;SGA_TARGET&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;No change to the application code is required.  There is no performance improvement to be obtained by customising the application code, either to add the REUSE STORAGE option to the TRUNCATE TABLE commands, nor to use DELETE commands instead.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Added 4.7.2009:&lt;/span&gt;Tests on Oracle 10.2.0.3 have shown that there is an advantage to putting the working storage tables into a Non-ASSM tablespace.  ASSM introduces additional blocks to map the storage in a segment.  These are also maintained during a truncate.  No having to maintain these blocks saved me 25% on the elapsed run time on some T&amp;L batch processes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Oracle Bug 4224840/4260477&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Added 2.4.2009:&lt;/span&gt;Unfortunately, nothing is quite as simple as it seems.  If you have a transaction that locks more than 4095 rows in a 32Kb block you can encounter block corruption (bug 4224840).  The fix/workaround in Oracle 10g (bug 4260477) is that a transaction will fail with this message before the corruption occurs.&lt;br /&gt;&lt;br /&gt;There is an excellent explanation of this problem, and a test script to reproduce it, on &lt;a target="_blank" href="http://hemantoracledba.blogspot.com/2008/08/testing-bug-4260477-fix-for-bug-4224840.html"&gt;Hermant's Oracle DBA Blog&lt;/a&gt;&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;ORA-08007: Further changes to this block by this transaction not allowed&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This error will not be resolved until Oracle 11g. However, it does not occur with smaller block sizes.  The workaround is either to commit more frequently, or to move the table concerned back to a tablespace with a smaller block size.  I have run into this with Time &amp;amp; Labor in a particular scenario.&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-7987170379477136396?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/7987170379477136396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=7987170379477136396&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/7987170379477136396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/7987170379477136396'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/01/performance-implications-of-concurrent.html' title='Factors Affecting Performance of Concurrent Truncate of Working Storage Tables'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25740336.post-594915060850633893</id><published>2009-01-06T19:15:00.006Z</published><updated>2009-01-06T20:17:43.109Z</updated><title type='text'>PeopleSoft's PSADMIN Role</title><content type='html'>Recently, I have had a number of conversations about the privileges that are granted to the PeopleSoft &lt;span style="font-style: italic;"&gt;OWNERID&lt;/span&gt; account (usually &lt;span style="font-style: italic;"&gt;SYSADM&lt;/span&gt;) via the &lt;span style="font-style: italic;"&gt;PSADMIN&lt;/span&gt; role.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://tech.groups.yahoo.com/group/psftdba/message/3527"&gt;A posting on the PeopleSoft DBA Forum&lt;/a&gt;, referenced Tanel Poder's blog entry: &lt;a target="_blank" href="http://blog.tanelpoder.com/2007/11/10/oracle-security-all-your-dbas-are-sysdbas-and-can-have-full-os-access/" rel="bookmark"&gt;Oracle Security: All your DBAs are SYSDBAs and can have full OS access&lt;/a&gt;.  Essentially, there is a security bug in Oracle where users with &lt;span style="font-style: italic;"&gt;IMP_FULL_DATABASE&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;BECOME_USER&lt;/span&gt; can gain &lt;span style="font-style: italic;"&gt;SYSDBA&lt;/span&gt; access.  This hole has been closed up a patch delivered in the July 2008 Critical Patch Update.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;PSADMIN&lt;/span&gt; role has both of these privileges, as well as another 22 that are not required for normal operation of a PeopleSoft system.&lt;br /&gt;&lt;br /&gt;There are two morals to this story:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There are good reasons to keep up to date with Oracle's CPUs.&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;PSADMIN&lt;/span&gt; has privileges that if given to application accounts could compromise database security.&lt;br /&gt;  &lt;/li&gt;&lt;/ol&gt; I think that &lt;span style="font-style: italic;"&gt;PSADMIN&lt;/span&gt; could be stripped down to just the following 8 privileges:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ANALYZE ANY&lt;/li&gt;&lt;li&gt;ALTER SESSION&lt;/li&gt;&lt;li&gt;CREATE SESSION&lt;/li&gt;&lt;li&gt;CREATE TABLE&lt;/li&gt;&lt;li&gt;CREATE TRIGGER&lt;/li&gt;&lt;li&gt;CREATE_VIEW&lt;/li&gt;&lt;li&gt;SELECT_CATALOG_ROLE&lt;/li&gt;&lt;li&gt;ALTER USER&lt;/li&gt;&lt;/ul&gt;You only need &lt;span style="font-style: italic;"&gt;CREATE USER&lt;/span&gt; when creating the PeopleSoft database with the Data Mover import.  &lt;span style="font-style: italic;"&gt;SELECT_CATALOG_ROLE&lt;/span&gt; is not in the delivered &lt;span style="font-style: italic;"&gt;PSADMIN&lt;/span&gt;, but is required if you remove &lt;span style="font-style: italic;"&gt;IMP_FULL_DATABASE&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;EXP_FULL_DATABASE&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Each privilege is discussed in Chapter 3 of &lt;a target="_blank" href="http://www.psftdba.com/"&gt;PeopleSoft for the Oracle DBA&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-594915060850633893?l=blog.psftdba.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.psftdba.com/feeds/594915060850633893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25740336&amp;postID=594915060850633893&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/594915060850633893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25740336/posts/default/594915060850633893'/><link rel='alternate' type='text/html' href='http://blog.psftdba.com/2009/01/peoplesofts-psadmin-role.html' title='PeopleSoft&apos;s PSADMIN Role'/><author><name>David Kurtz</name><uri>http://www.blogger.com/profile/00924323960047469300</uri><email>info@go-faster.co.uk</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06899385033627209420'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>