The most important challenge to performance tuning is knowing what to optimize. To improve the performance of your application, identify the areas of your application that do not operate at peak efficiency. This section contains information about these subjects:
Task 1: Measure EclipseLink Performance with the EclipseLink Profiler
Task 2: Measure EclipseLink Performance in the Server Environment
Task 4: Identify Sources of Application Performance Problems
EclipseLink provides a diverse set of features to measure and optimize application performance. You can enable or disable most features in the descriptors or session, making any resulting performance gains global.Performance considerations are present at every step of the development cycle. Although this implies an awareness of performance issues in your design and implementation, it does not mean that you should expect to achieve the best possible performance in your first pass.
For example, if optimization complicates the design, leave it until the final development phase. You should still plan for these optimizations from your first iteration, to make them easier to integrate later.
The most important concept associated with tuning your EclipseLink application is the idea of an iterative approach. The most effective way to tune your application is to do the following tasks:
The EclipseLink performance profiler helps you identify performance problems by logging performance statistics for every executed query in a given session. Use the performance profiler to monitor a single query, or simple single-threaded use case.
The EclipseLink performance profiler logs the following information to the log file.
Table 18-1 Information Logged by the EclipseLink Performance Profiler
Information Logged | Description |
---|---|
Query Class |
Query class name. |
Domain Class |
Domain class name. |
Total Time |
Total execution time of the query, including any nested queries (in milliseconds). |
Local Time |
Execution time of the query, excluding any nested queries (in milliseconds). |
Number of Objects |
The total number of objects affected. |
Number of Objects Handled per Second |
How many objects were handled per second of transaction time. |
Logging |
the amount of time spent printing logging messages (in milliseconds). |
SQL Prepare |
The amount of time spent preparing the SQL script (in milliseconds). |
SQL Execute |
The amount of time spent executing the SQL script (in milliseconds). |
Row Fetch |
The amount of time spent fetching rows from the database (in milliseconds) |
Cache |
The amount of time spent searching or updating the object cache (in milliseconds) |
Object Build |
The amount of time spent building the domain object (in milliseconds) |
query Prepare |
the amount of time spent to prepare the query prior to execution (in milliseconds) |
SQL Generation |
the amount of time spent to generate the SQL script before it is sent to the database (in milliseconds) |
The EclipseLink performance profiler is an instance of org.eclipse.persistence.tools.profiler.PerformanceProfiler
class. To enable it, add the following line to the persistence.xml
file:
<property name="eclipselink.profiler" value="PerformanceProfiler.logProfiler"/>
In addition to enabling the EclipseLink profiler, The PerformanceProfiler
class public API also provides the functionality described in Table 18-2:
Table 18-2 Additional PerformanceProfiler Functionality
To... | Use... |
---|---|
Disable the profiler |
|
Organize the profiler log into a summary of all the individual operation profiles including operation statistics like the shortest time of all the operations that were profiled, the total time of all the operations, the number of objects returned by profiled queries, and the total time that was spent in each kind of operation that was profiled |
|
Organize the profiler log into a summary of all the individual operation profiles by query |
|
Organize the profiler log into a summary of all the individual operation profiles by class. |
|
You can see profiling results by opening the profile log in a text reader, such as Notepad.
The profiler output file indicates the health of a EclipseLink-enabled application.
Example 18-7 shows an sample of the EclipseLink profiler output.
Example 18-7 Performance Profiler Output
Begin Profile of{ ReadAllQuery(com.demos.employee.domain.Employee) Profile(ReadAllQuery,# of obj=12, time=139923809,sql execute=21723809, prepare=49523809, row fetch=39023809, time/obj=11623809,obj/sec=8) } End Profile
Example 18-7 shows the following information about the query:
ReadAllQuery(com.demos.employee.domain.Employee)
: specific query profiled, and its arguments.
Profile(ReadAllQuery
: start of the profile and the type of query.
# of obj=12
: number of objects involved in the query.
time=139923809
: total execution time of the query (in milliseconds).
sql execute=21723809
: total time spent executing the SQL statement.
prepare=49523809
: total time spent preparing the SQL statement.
row fetch=39023809
: total time spent fetching rows from the database.
time/obj=116123809
: number of nanoseconds spent on each object.
obj/sec=8
: number of objects handled per second.
Use the Performance Monitor to provide detailed profiling and monitoring information in a multithreaded server environment. Use the performance monitor to monitor a server, multiple threads, or long running processes.
Enable the monitor in persistence.xml
file as follows:
<property name="eclipselink.profiler" value="PerformanceMonitor"/>
The performance monitor can also be enabled through code using a SessionCustomizer
.
The performance monitor will output a dump of cumulative statistics every minute to the EclipseLink log. The statistics contains three sets of information:
Info; statistics that are constant informational data, such as the session name, or time of login.
Counter; statistics that are cumulative counters of total operations, such as cache hits, or query executions.
Timer; statistics that are cumulative measurements of total time (in nano seconds) for a specific type of operation, reading, writing, database operations.
Statistics are generally grouped in total and also by query type, query class, and query name. Counters and timers are generally recorded for the same operations, so the time per operation could also be calculated.
The time between statistic dumps can be configured by using the setDumpTime(long)
method in the PerformanceMonitor
class. If dumping the results is not desired, then the dumpTime
attribute can be set to be very large such as Long.MAX_VALUE
. The statistic can also be accessed in a Java program with the getOperationTime(String)
method.
The performance monitor can also be configured with a profile weight. The profile weights are defined in the SessionProfiler
class and used by the PerformanceMonitor class. The weights include:
NONE
—No statistics are recorded.
NORMAL
—Informational statistics are recorded.
HEAVY
—Informational, counter and timer statistics are recorded.
ALL
—All statistics are recorded (this is the default).
Note: In the current release, the performance monitor responds with the same information for the |
Use the Fetch Group Monitor to measure fetch group field usage. This can be useful for performance analysis in a complex system.
Enable this monitor by using the system property org.eclipse.persistence.fetchgroupmonitor=true
.
The monitor outputs the attribute used for a class every time a new attribute is accessed.
Areas of the application where performance problems could occur include the following:
Identifying General Performance Optimization
Schema
Mappings and Descriptors
Sessions
Cache
Data Access
Queries
Unit of Work
Application Server and Database Optimization
Task 5: Modify Poorly-Performing Application Components provides some guidelines for dealing with problems in each of these areas.
For each source of application performance problems listed in Task 4: Identify Sources of Application Performance Problems, you can try specific workarounds, as described in this section.
Avoid overriding EclipseLink default behavior unless your application requires it. Some of these defaults are suitable for a development environment; you should change these defaults to suit your production environment. These defaults may include:
Batch writing – See "jdbc.batch-writing" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
Statement caching – See "jdbc.cache-statements" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
Read and write connection pool size – See "connection-pool" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
Session cache size – See "maintain-cache" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
Use the Workbench rather than manual coding. These tools are not only easy to use: the default configuration they export to deployment XML (and the code it generates, if required) represents best practices optimized for most applications.
Optimization is an important consideration when you design your database schema and object model. Most performance issues occur when the object model or database schema is too complex, as this can make the database slow and difficult to query. This is most likely to happen if you derive your database schema directly from a complex object model.
To optimize performance, design the object model and database schema together. However, allow each model to be designed optimally: do not require a direct one-to-one correlation between the two.
Possible ways to optimize the schema include:
Aggregating two tables into one
Splitting one table into many
Using a collapsed hierarchy
Choosing one out of many
See "Data Storage Schema" in EclipseLink Concepts for additional information.
If you find performance bottlenecks in your mapping and descriptors, try these solutions:
Always use indirection (lazy loading). It is not only critical in optimizing database access, but also allows EclipseLink to make several other optimizations including optimizing its cache access and unit of work processing. See "cache-usage" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
Avoid using method access in your EclipseLink mappings, especially if you have expensive or potentially dangerous side-effect code in your get or set methods; use the default direct attribute access instead. See "Using Method or Direct Field Access" in the EclipseLink Concepts.
Avoid using the existence checking option checkCacheThenDatabase on descriptors, unless required by the application. The default existence checking behavior offers better performance. See "@ExistenceChecking" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
Avoid expensive initialization in the default constructor that EclipseLink uses to instantiate objects. Instead, use lazy initialization or use an EclipseLink instantiation policy to configure the descriptor to use a different constructor. See "@InstantiationCopyPolicy" in Jakarta Persistence API (JPA) Extensions Reference for EclipseLink.
You can often improve performance through caching, even in a clustered environment by implementing cache coordination. Cache coordination allows multiple, possibly distributed instances of a session to broadcast object changes among each other so that each session's cache can be kept up-to-date. For detailed information about optimizing cache behavior, see "Understanding Caching" in EclipseLink Concepts and the following examples:
Depending on the type of data source your application accesses, EclipseLink offers a variety of Login
options that you can use to tune the performance of low level data reads and writes. For optimizing higher-level data reads and writes, "Understanding Data Access" in EclipseLink Concepts offers several techniques to improve data access performance for your application. These techniques show you how to:
Optimize JDBC driver properties.
Optimize data format.
Use batch writing for optimization.
Use Outer-Join Reading with Inherited Subclasses.
Use Parameterized SQL (Parameter Binding) and Prepared Statement Caching for Optimization.
EclipseLink provides an extensive query API for reading, writing, and updating data. "Understanding EclipseLink Queries" in EclipseLink Concepts offers several techniques to improve query performance for your application. These techniques show you how to:
Use parameterized SQL and prepared statement caching for optimization.
Use named queries for optimization.
Use batch and join reading for optimization.
Use partial object queries and fetch groups for optimization.
Use read-only queries for optimization.
Use JDBC fetch size for optimization.
Use cursored streams and scrollable cursors for optimization.
Use result set pagination for optimization.
It also includes links to read and write optimization examples.
To optimize the application server and database performance, consider these techniques:
Configuring your application server and database correctly can have a big impact on performance and scalability. Ensure that you correctly optimize these key components of your application in addition to your EclipseLink application and persistence.
For your application or Jakarta EE server, ensure your memory, thread pool and connection pool sizes are sufficient for your server's expected load, and that your JVM has been configured optimally.
Ensure that your database has been configured correctly for optimal performance and its expected load.
Finally, after identifying possible performance bottlenecks and taking some action on them, rerun your application, again with the profiler enabled (see Enabling the EclipseLink Profiler). Review the results and, if more action is required, follow the procedures outlined in Task 5: Modify Poorly-Performing Application Components.