ADF is a highly productive but somewhat complex framework, and has evolved to optimize the default settings for better performance. But there are many options which depend on the specific application and use case, so here are are few pain points and solutions that you should consider for better performance of your ADF applications.
It is very important to note that performance should be considered from the design phase of your application vs. an afterthought. This seems obvious, but too often we see customers/developers struggle to make sure that happens.
Business Components
- Make sure to “appropriately set Row Level Bind Values for View Accessors to false or true” as necessary. See blog for more details. This value would mostly be set to “false”. Be aware that JDeveloper at times resets this value to blank, which means true and it may not be desired for your situation.
- There is a memory leak in this situation, if your Application Modules are alive for longer duration without being recycled.
- You will also notice Performance degradation over time.
- You can use DBSequence for generated key attributes or you can override create method to programmatically generate key.
- Either option works, but if you want to enable JDBC Batching for Performance, you can not use DBSequence.
- It is best to standardize on one option for entire development team to promote consistency. So i would recommend use of create method or groovy expression to programmatically generate keys. This is very well documented in various blogs. Here is sample groovy code.
(new oracle.jbo.server.SequenceImpl("MY_TABLE_SEQ", adf.object.getDBTransaction())).getSequenceNumber()
- ADF BC State Persistence
- ADF BC will persist it’s state to PS_TXN table. You will need to work with your Database team to tune access to this table, if you run into performance issues.
- Setup at least daily purge for PS_TXN table.
- SQL Scripts for creating tables (adfbc_create_statesnapshottables.sql) and purge (bc4jcleanup.sql) are available in JDeveloper installation at <JDeveloper Install Directory>\oracle_common\modules\oracle.adf.model_12.1.3\bin.
- Your goal should be minimize such persistence and subsequent activation as that can deteriorate performance of your application. This can be achieved by setting up higher value for Application Module reference pool. Configure this value such that reference pool number * number of managed servers in cluster equals to total number of unique sessions in 30 minutes. This is just a simple rule that i have devised, note that this will require you to tune JVM memory settings as more number of Application module will be active in memory.
- View Object tuning
- You can use Forward Only mode in non UI access of View Object. For example, background processing. Forward Only access is very efficient.
- You may have to use Query Hint like FIRST_ROWS(1001), to give hint to database optimizer about your intentions that you are only interested in first 1001 rows.
- Use Retrieve in Batches of Range Size +1. This will allow efficient retrieval of data from database ResultSet. This is extremely important as this value defaults to 1 when you create View Object.
- Avoid persisting Transient attributes, if their values can be derived from other attributes. Be careful when checking “Including All Transient Values”.
Read our report, State of DevOps: Best Practice Adoption to find out.
- Disconnect Application Module on Release.
- ADF will not release database connection back to Data Source by default, which can lead to high connection usage and application may eventually get in to hung situation if you run out of Data Source connections.
- Setting this option will make sure that connection is released back to Data Source pool and you can keep more number of active application modules in memory without requiring high number of data source connections.
ADF Faces
- Tune org.apache.myfaces.trinidad.CLIENT_STATE_MAX_TOKENS appropriately.
- Token based client side state saving is enabled by default. Browser will pass token indicating reference to page state and page state is stored in HTTP Session. You can inspect token value using tool like Fiddler.
- There are 15 such page state instances maintained in HTTP Session, which can lead to unnecessary memory usage for applications with large number of users.
- You can not set this value to 1, as you need to allow for use of Back button and Chrome & Firefox share session across all tabs & windows. So if you set this value to 1, Users will be able to launch only 1 tab for that application.
- Cache static content like .js, .css, .png etc.
- You can cache static content in your Load Balancer.
- Make sure that browser history is also maintained. IE has settings that can clear Browser History on exit.
- Monitor access logs to validate content caching.
- If using Oracle Access Manager
- Default settings of Oracle Access Manger prevents caching of content on Client end, you will need to correct the cache-control header variables in OAM, so that it does not insert headers to disable caching.
- Enable Compression as needed.
- ADF significantly reduces bandwidth requirements over traditional (non AJAX) JSP applications.
- If you have users connecting over slower connections, you may want to enable compression to reduce communication time.
WebLogic
- Enable Garbage collection logs.
- Add -verbose:gc to server start arguments. If you are using JRockit, add -XverboseTimeStamp as well.
- Enable Heap dump on Out of Memory.
- Add -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/<Server Name> to Server Start parameters. Make sure you have enough space for this directory and <Server Name> folder is created. Ideally, you should just use a separate mount point specifically for Heap Dumps if running on UNIX.
- You can use Eclipse MAT, which seems to work perfectly for heap analysis.
- Add command line parameters to allows for JMX connection from JRockit Mission Control or JConsole.
- Add -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=<Port#> to Server Start Parameters. Define a new port for each Server for this purpose.
- You can also run Profiling using JRockit Mission Control, to monitor time spent in specific methods. This is unique feature of JRMC that is not yet available in JConsole.
- Print time spent in access logs.
- Use Extended format for HTTP Logs with c-ip date time cs-method cs-uri sc-status bytes time-taken.
- If you have Apache or OHS in front of WebLogic server, make sure to update it’s log format to print time spent at the end.
- Use
100 for your Data Sources to time out long running queries. This example is set for 100 seconds timeout, you can tune it as per your needs.- You can customize the Exception Handler to provide proper message to user for such timeout situations.
Learn how to deliver better quality software faster, with less cost and risk.