18 Enhancing Performance

This chapter describes Oracle TopLink performance features, provided by EclipseLink, and how to monitor and optimize EclipseLink-enabled applications.

This chapter includes the following sections:

Use Case

Users want to improve the performance of their TopLink-enabled application.

Solution

TopLink provides many configuration options that can improve performance, such as caching. In addition, there are ways to improve the performance of specific functions, such as using Join Fetching for queries.

Components

  • TopLink 12c (12.1.2.0.0) or later.

    Note:

    TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle.

Sample

See the following EclipseLink samples for related information:

18.1 Performance Features

EclipseLink includes a number of performance features that make it the industry's best performing and most scalable JPA implementation. These features include:

18.1.1 Object Caching

The EclipseLink cache is an in-memory repository that stores recently read or written objects based on class and primary key values. The cache helps improve performance by holding recently read or written objects and accessing them in-memory to minimize database access.

Caching allows you to:

  • Set how long the cache lives and the time of day, a process called cache invalidation.

  • Configure cache types (Weak, Soft, SoftCache, HardCache, Full) on a per entity basis.

  • Configure cache size on a per entity basis.

  • Coordinate clustered caches.

18.1.1.1 Caching Annotations

EclipseLink defines these entity caching annotations:

  • @Cache

  • @TimeOfDay

  • @ExistenceChecking

EclipseLink also provides a number of persistence unit properties that you can specify to configure the EclipseLink cache (see "Persistence Property Extensions Reference" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink). These properties might compliment or provide an alternative to the usage of annotations.

18.1.1.2 Using the @Cache Annotation

EclipseLink uses identity maps to cache objects in order to enhance performance, as well as maintain object identity. You can control the cache and its behavior by using the @Cache annotation in your entity classes. Example 18-1 shows how to implement this annotation.

Example 18-1 Using the @Cache Annotation

@Entity
 @Table(name="EMPLOYEE")
 @Cache (
     type=CacheType.WEAK,
     isolated=false,
     expiry=600000,
     alwaysRefresh=true,
     disableHits=true,
     coordinationType=INVALIDATE_CHANGED_OBJECTS
     )
 public class Employee implements Serializable {
     ...
 }

For more information about object caching and using the @Cache annotation, see "@Cache" in the Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.2 Querying

The scope of a query, the amount of data returned, and how that data is returned can all affect the performance of a EclipseLink-enabled application. EclipseLink query mechanisms enhance query performance by providing these features:

This section describes how these features improve performance.

18.1.2.1 Read-only Queries

EclipseLink uses the eclipselink.read-only hint, QueryHint (@QueryHint) to retrieve read-only results back from a query. On nontransactional read operations, where the requested entity types are stored in the shared cache, you can request that the shared instance be returned instead of a detached copy.

For more information about read-only queries, see the documentation for the read-only hint in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.2.2 Join Fetching

Join Fetching enhances performance by enabling the joining and reading of the related objects in the same query as the source object. Enable Join Fetching by using the @JoinFetch annotation, as shown in Example 18-2. This example shows how the @JoinFetch annotation specifies the Employee field managedEmployees.

Example 18-2 Enabling JoinFetching

@Entity
 public class Employee implements Serializable {
     ...
     @OneToMany(cascade=ALL, mappedBy="owner")
     @JoinFetch(value=OUTER)
     public Collection<Employee> getManagedEmployees() {
         return managedEmployees;
     }
     ...
 }

For more details on Join Fetching, see "@JoinFetch" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.2.3 Batch Reading

The eclipselink.batch hint supplies EclipseLink with batching information so subsequent queries of related objects can be optimized in batches instead of being retrieved one-by-one or in one large joined read. Batch reading is more efficient than joining because it avoids reading duplicate data. Batching is only allowed on queries that have a single object in their select clause.

18.1.2.4 Fetch Size

If you have large queries that return a large number of objects you can improve performance by reducing the number database hits required to satisfy the selection criteria. To do this, use the The eclipselink.jdbc.fetch-size hint. This hint specifies the number of rows that should be fetched from the database when more rows are required (depending on the JDBC driver support level). Most JDBC drivers default to a fetch size of 10, so if you are reading 1000 objects, increasing the fetch size to 256 can significantly reduce the time required to fetch the query's results. The optimal fetch size is not always obvious. Usually, a fetch size of one half or one quarter of the total expected result size is optimal. Note that if you are unsure of the result set size, incorrectly setting a fetch size too large or too small can decrease performance.

18.1.2.5 Pagination

Slow paging can result in significant application overhead; however, EclipseLink includes a variety of solutions for improving paging results; for example, you can:

  • Configure the first and maximum number of rows to retrieve when executing a query.

  • Perform a query on the database for all of the ID values that match the criteria and then use these values to retrieve specific sets.

  • Configure EclipseLink to return a ScrollableCursor object from a query by using query hints. This returns a database cursor on the query's result set and allows the client to scroll through the results page by page.

For details on improving paging performance, see "How to use EclipseLink Pagination" in the EclipseLink online documentation, at:

http://wiki.eclipse.org/EclipseLink/Examples/JPA/Pagination#How_to_use_EclipseLink_Pagination

18.1.2.6 Cache Usage

EclipseLink uses a shared cache mechanism that is scoped to the entire persistence unit. When operations are completed in a particular persistence context, the results are merged back into the shared cache so that other persistence contexts can use them. This happens regardless of whether the entity manager and persistence context are created in Java SE or Java EE. Any entity persisted or removed using the entity manager will always be kept consistent with the cache.

You can specify how the query should interact with the EclipseLink cache by using the eclipselink.cache-usage hint. For more information, see "cache usage" in tJava Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.3 Mapping

Mapping performance is enhanced by these features:

This section describes these features.

18.1.3.1 Read-Only Objects

When you declare a class read-only, clones of that class are neither created nor merged greatly improving performance. You can declare a class as read-only within the context of a unit of work by using the addReadOnlyClass() method.

  • To configure a read-only class for a single unit of work, specify that class as the argument to addReadOnlyClass():

    myUnitofWork.addReadOnlyClass(B.class);
    
  • To configure multiple classes as read-only, add them to a vector and specify that vector as the argument to addReadOnlyClass():

    myUnitOfWork.addReadOnlyClasses(myVectorOfClasses);
    

For more information about using read-only objects to enhance performance, see "@ReadOnly" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.3.2 Weaving

Weaving is a technique of manipulating the byte-code of compiled Java classes. The EclipseLink JPA persistence provider uses weaving to enhance both JPA entities and Plain Old Java Object (POJO) classes for such things as lazy loading, change tracking, fetch groups, and internal optimizations.Weaving can be performed either dynamically at runtime, when entities are loaded, or statically at compile time by post-processing the entity .class files. By default, EclipseLink uses dynamic weaving whenever possible. This includes inside an Java EE 5/6 application server and in Java SE when the EclipseLink agent is configured. Dynamic weaving is recommended as it is easy to configure and does not require any changes to a project's build process

For details on how to use weaving to enhance application performance, see "weaving" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.4 Transactions

To optimize performance during data transactions, use change tracking,. Change tracking allows you to tune the way EclipseLink detects changes that occur during a transaction. You should choose the strategy based on the usage and data modification patterns of the entity type as different types may have different access patterns and hence different settings, and so on.

Enable change tracking by using the @ChangeTracking annotation, as shown in Example 18-3.

Example 18-3 Enabling Change Tracking

@Entity
@Table(name="EMPLOYEE")
@ChangeTracking(OBJECT) (
public class Employee implements Serializable {
    ...
}

For more details on change tracking, see "@ChangeTracking" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.5 Database

Database performance features in EclipseLink include:

This section describes these features.

18.1.5.1 Connection Pooling

Establishing a connection to a data source can be time-consuming, so reusing such connections in a connection pool can improve performance. EclipseLink uses connection pools to manage and share the connections used by server and client sessions. This feature reduces the number of connections required and allows your application to support many clients.

By default, EclipseLink sessions use internal connection pools. These pools allow you to optimize the creation of read connections for applications that read data only to display it and only infrequently modify data. The also allow you to use Workbench to configure the default (write) and read connection pools and to create additional connection pools for object identity or any other purpose.

In addition to internal connection pools, you can also configure EclipseLink to use any of these types of connection pools:

  • External connection pools; you must use this type of connection pool to integrate with external transaction controller (JTA).

  • Default (write) and read connection pools;

  • Sequence connection pools; Use these types of pools when your application requires table sequencing (that is, non-native sequencing) and you are using an external transaction controller. Application-specific connection pools; These are connection pools that you can create and use for any application purpose, provided you are using internal EclipseLink connection pools in a session.

For more information about using connection pools with EclipseLink, see the following topics in Understanding Oracle TopLink:

  • "Understanding Connections"

  • "Understanding Connection Pools"

18.1.5.2 Parameterized SQL and Statement Caching

Parameterized SQL can prevent the overall length of an SQL query from exceeding the statement length limit that your JDBC driver or database server imposes. Using parameterized SQL along with prepared statement caching can improve performance by reducing the number of times the database SQL engine parses and prepares SQL for a frequently called query

By default, EclipseLink enables parameterized SQL but not prepared statement caching. You should enable statement caching either in EclipseLink when using an internal connection pool or in the data source when using an external connection pool and want to specify a statement cache size appropriate for your application.

To enable parameterized SQL, add this line to the persistence.xml file that is in the same path as your domain classes:

<property name="eclipselink.jdbc.bind-parameters" value="true"/>

To disable parameterized SQL, change value= to false.

For more information about using parameterized SQL and statement caching, see "jdbc.bind-parameters" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.1.5.3 Batch Writing

Heterogeneous batch writing is an optimization that allows EclipseLink to send multiple heterogeneous dynamic SQL statements to the database to be executed as a single batch. Batch writing is best used for applications that perform multiples writes in each transaction.

To configure batch writing, include the eclipselink.jdbc.batch-writing and eclipselink.jdbc.batch-writing.size properties in the persistence.xml file. The following example enables Oracle's native batch writing feature that is available with the Oracle JDBC driver and configures the batch size to 150 statements:

<property name="eclipselink.jdbc.batch-writing" value="Oracle-JDBC"/>
<property name="eclipselink.jdbc.batch-writing.size" value="150"/>

Different batch options are supported and custom batch implementations can also be used. For a detailed reference of the batch writing properties, see the batch-writing and batch-writing.size documentation in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

For details on using batch writing on Exalogic, see "Task 4: Configure Heterogeneous Batch Writing on Exalogic".

18.1.5.4 Serialized Object Policy

Serialized object policy is an optimization that allows EclipseLink to write out the whole entity object with its privately owned (and nested privately owned) entities and element collections into an additional field in the database. Serialized object policy optimizes fetching from the database, provides faster database reads, and reduces middle tier CPU and network access in certain situations.

Serialized object policy is best for read-only or read-mostly applications and should only be used for entities that load all their dependent entities or element collections. When using serialized object policy, database write operations (insert and update) are slower and queries for objects without private-owned data are slower. See "A Simple Serialized Object Policy Example" that demonstrates when serialized object policy is best used to increase performance.

Consider using serialized object policy only for complex objects with numerous aggregation as characterized by:

  • Multiple database rows mapped to a single Java object

  • When the object is read from the database all these rows are read at once (no indirection, or all indirection always triggered). There may be un-triggered indirection for other fields that are not included in the serialized object policy field

  • If versionning is used, then updating or deleting any mapped row (or inserting of a new one) should result in incrementing of the object's version

  • Object deletion causes all the rows to be deleted.

  • Irregular structure of the aggregation makes it less possible to use other common optimizations (such as join fetching and batch reading).

Serialized Object Policy Configuration

Serialized object policy is enabled by using the @SerializedObject annotation on an entity or mapped superclass and passing in an implementation of the SerializedObjectPolicy interface. You must provide an implementation of this interface; there is no default implementation. The annotations also includes a field to define the column name for the object in the database. The default column name is SOP.

Example 18-4 enables serialized object policy, overrides the default column name, and sets optimistic locking to cascade, which can increase performance by keeping the serialized object policy field in the database up-to-date.

Note:

If serialized object policy is set on an entity, then policies with the same fields are set on all inheriting entities.

Example 18-4 Enabling Serialized Object Policy Using Annotations

@Entity
@SerializedObject(MySerializedObjectPolicy.class)
@OptimisticLocking(cascade = true) 
public class Employee implements Serializable {
... 
 
@Entity
@SerializedObject(MySerializedObjectPolicy.class, column = @Column(name="ADDR_SOP"))
@OptimisticLocking(cascade = true)
public class Address implements Serializable {
...

Example 18-5 enables serialized object policy in the eclipselink-orm.xml file

Example 18-5 Enabling Serialized Object Policy Using eclipselink-orm.xml

<entity class="Employee">
    <optimistic-locking cascade="true">
    <serialized-object class="MySerializedObjectPolicy">
</entity>

<entity class="Address">
    <optimistic-locking cascade="true">
    <serialized-object class="MySerializedObjectPolicy">
        <column name="ADDR_SOP"/>
    </serialized-object>
</entity>

Example 18-6 enables serialized object policy in a customizer (either session or descriptor):

Example 18-6 Enabling Serialized Object Policy in a Customizer

if (descriptor.hasSerializedObjectPolicy()) {

    MySerializedObjectPolicy sop = (MySerializedObjectPolicy)descriptor.
       getSerializedObjectPolicy();

    // to compare pk cached in SOP Object with pk read directly from the row from
    //pk field(s) (false by default):

    sop.setShouldVerifyPrimaryKey(true);

    // to NOT compare version cached in SOP Object with version read directly from
    // the row from version field (true by default):

    sop.setShouldVerifyVersion(false);

    // to define recoverable SOP (false by default):

    sop.setIsRecoverable(true);
}

To use a descriptor customizer, define the class and specify it using the @Customizer annotation:

public class MyDescriptorCustomizer implements
   org.eclipse.persistence.config.DescriptorCustomizer {
    public void customize(ClassDescriptor descriptor) throws Exception 
    {
         ...
    }
}
...
@Customizer(MyDescriptorCustomizer.class)
public class Employee implements Serializable {... 

To use a session customizer to reach all descriptors at once, specify it in a persistence unit property:

public class MySessionCustomizer implements
   org.eclipse.persistence.config.SessionCustomizer {
    public void customize(Session session) throws Exception 
    {
        for (ClassDescriptor descriptor : session.getDescriptors().values()) {
            ...        
        }
    }
}
 
<property name="eclipselink.session.customizer" value="MySessionCustomizer"/>

Read queries (including find and refresh) automatically use a serialized object if serialized object policy is enabled. If the serialized object column contains null, or an obsolete version of the object, then a query using a serialized object policy would either throw an exception or, if all other fields have been read as well, build the object using these fields (exactly as in the case where a serialized object policy is not used).

To disable querying the serialized object, set the SERIALIZED_OBJECT property to false as part of a query hint. For example:

Query query = em.createQuery("SELECT e FROM Employee e")
   .setHint(QueryHints.SERIALIZED_OBJECT, "false");

The following example demonstrates disabling searching for a serialized object:

Map hints = new HashMap();
hints.put("eclipselink.serialized-object", "false");
Employee emp = em.find(Employee.class, id, hints);

Applications that use serialized object policy should also consider using the result set access optimization. Use the optimization when querying to avoid the costly reading of the serialized object policy field (which can be large) if it is already cached and the query is not a refresh query. The optimization ensures that only the primary key is retrieved from the result set and only gets additional values if the cached object cannot be used. To enable the result set access optimization, set the eclipselink.jdbc.result-set-access-optimization persistent unit property to true in the persistence.xml file. For example:

<property name="eclipselink.jdbc.result-set-access-optimization" value="true"/>

A Simple Serialized Object Policy Example

Consider the following example object model:

@Entity(name="SOP_PartOrWhole")
@Table(name="SOP_PART_OR_WHOLE")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@Index(columnNames={"LEFTPART_ID", "RIGHTPART_ID"})
public abstract class PartOrWhole implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    public long id;
 
    protected String description = "";
    
    @OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
    protected Part leftPart; 
    @OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
    protected Part rightPart;
}
 
@Entity(name="SOP_Whole")
@DiscriminatorValue("W")
@SerializedObject(MySerializedObjectPolicy.class)
@NamedQueries({
    @NamedQuery(name="findWhole", query="Select w from SOP_Whole w where w.id =
    :id", hints= @QueryHint(name="eclipselink.serialized-object", value="false")),
    @NamedQuery(name="findWholeSOP", query="Select w from SOP_Whole w where w.id =
    :id"),
})
public class Whole extends PartOrWhole {
}
 
@Entity(name="SOP_Part")
@DiscriminatorValue("P")
public class Part extends PartOrWhole {
}

The above data model allows the construction of a Whole object with any number of (nested) Part objects. For example:

  • 1 level – A Whole object contains left and right Part objects (3 objects all together)

  • 2 levels – A Whole object contains left and right Part objects; each of the Part objects has left and right Part objects (7 objects all together)

  • 3 levels – A Whole object contains left and right Part object; each of the Part objects has a left and right Part objects; which each have a left and right Part objects (15 objects all together)

  • n levels – (2n+1 - 1 objects all together)

Performance for the above data model increases as the number of levels in the model increases. For example:

  • 1 level – performance is slower than without serialized object policy.

  • 2 levels – performance is only slightly faster than without serialized object policy.

  • 5 levels – performance is 7 times faster than without serialized object policy.

  • 10 levels – performance is more than 25 times faster than without serialized object policy.

For details on using serialized object policy on Exalogic, see "Task 2: Use Serialized Object Policy on Exalogic".

18.1.6 Automated Tuning

Automated tuning is an optimization that allows applications to automatically tune JPA and session configuration for a specific purpose. Multiple configuration options can be configured by a single tuner and different configurations can be specified before and after application deployment and after application metadata has been processed but before connecting the session. Automated tuning simplifies configuration and allows a dynamic single tuning option.

Tuners are created by implementing the org.eclipse.persistence.tools.tuning.SessionTuner interface. Two tuner implementations are provided and custom tuners can be created as required:

  • Standard (StandardTuner) – The standard tuner is enabled by default and does not change any of the default configuration settings.

  • Safe (SafeModeTuner) – The safe tuner configures the persistence unit for debugging. It disables caching and several performance optimizations to provide a simplified debugging and development configuration:

    WEAVING_INTERNAL = false
    WEAVING_CHANGE_TRACKING = false
    CACHE_SHARED_DEFAULT = false
    JDBC_BIND_PARAMETERS = false
    ORM_SCHEMA_VALIDATION = true
    TEMPORAL_MUTABLE = true
    ORDER_UPDATES = true
    

To enable a tuner, specify a predefined tuner or enter the fully qualified name of a SessionTuner implementation as the value of the eclipselink.tuning property in the persistence.xml file. The following example enables the safe tuner.

<property name="eclipselink.tuning" value="Safe"/>

For a detailed reference of the tuning property, see Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

For details on using the Exalogic automated tuner, see "Task 1: Enable the Exalogic Automated Tuner".

18.1.7 Tools

EclipseLink provides monitoring and optimization tools, as described in Section 18.2, "Monitoring and Optimizing EclipseLink-Enabled Applications".

18.2 Monitoring and Optimizing EclipseLink-Enabled Applications

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:

18.2.1 Performance Optimization Recommendations and Tips

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:

18.2.2 Task 1: Measure EclipseLink Performance with the EclipseLink Profiler

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)


18.2.2.1 Enabling the EclipseLink Profiler

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

dontLogProfile

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

logProfileSummary

Organize the profiler log into a summary of all the individual operation profiles by query

logProfileSummaryByQuery

Organize the profiler log into a summary of all the individual operation profiles by class.

logProfileSummaryByClass


18.2.2.2 Accessing and Interpreting Profiler Results

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.

18.2.3 Task 2: Measure EclipseLink Performance in the Server Environment

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 HEAVY and ALL values.

18.2.4 Task 3: Measure Fetch Group Field Usage

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.

18.2.5 Task 4: Identify Sources of Application Performance Problems

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.

18.2.6 Task 5: Modify Poorly-Performing Application Components

For each source of application performance problems listed in Section 18.2.5, "Task 4: Identify Sources of Application Performance Problems", you can try specific workarounds, as described in this section.

18.2.6.1 Identifying General Performance Optimizations

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 Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

  • Statement caching – See "jdbc.cache-statements" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

  • Read and write connection pool size – See "connection-pool" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

  • Session cache size – See "maintain-cache" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

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.

18.2.6.2 Schema

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 Understanding Oracle TopLink for additional information.

18.2.6.3 Mappings and Descriptors

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 Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

  • 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 Understanding Oracle TopLink.

  • 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 Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

  • 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 Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

18.2.6.4 Cache

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 Understanding Oracle TopLink and the following examples:

18.2.6.5 Data Access

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 Understanding Oracle TopLink 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.

18.2.6.6 Queries

EclipseLink provides an extensive query API for reading, writing, and updating data. "Understanding EclipseLink Queries" in Understanding Oracle TopLink 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.

18.2.6.7 Application Server and Database Optimization

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 Java 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.

18.2.7 Task 6: Measure Performance Again

Finally, after identifying possible performance bottlenecks and taking some action on them, rerun your application, again with the profiler enabled (see Section 18.2.2.1, "Enabling the EclipseLink Profiler"). Review the results and, if more action is required, follow the procedures outlined in Section 18.2.6, "Task 5: Modify Poorly-Performing Application Components".