Because of the L2 cache, this loop will perform one way the first time it is executed, and an-
other (generally faster) way on subsequent executions. The specific difference of that per-
formance depends on various details of the queries and the entity relationships. The next few
subsections will explain the results in detail.
The differences in this example are based in some cases on different JPA configurations, but
also because some tests are executed without traversing the relationship between the Stock
and StockOptions classes. In those tests without traversal of the relationship, the pro-
cessOptions value in the loop is false ; only the StockPrice objects are actually used.
Default caching (lazy loading)
In the sample code, the stock prices are loaded via a named query. In the default case, this
simple query is executed to load the stock data:
@NamedQuery ( name = "findAll" ,
query = "SELECT s FROM StockPriceImpl s ORDER BY s.id.symbol" )
The StockPrice class has a @OneToMany relationship with the StockOptionPrice class us-
ing the optionsPrices instance variable:
@OneToMany ( mappedBy = "stock" )
private Collection < StockOptionPrice > optionsPrices ;
@OneToMany relationships are loaded lazily by default. Table 11-3 shows the time to execute
Table 11-3. Seconds required to read data for 128 stocks (default configuration)
61.9 seconds (33,409 SQL calls) 3.2 seconds (1 SQL call)
Lazy relationship, no traversal 5.6 seconds (1 SQL call)
2.8 seconds (1 SQL call)
The first time the sample loop is executed in this scenario (for 128 stocks with one year of
data), the JPA code executes one SQL statement in the call to the executeQuery() method.
That statement is executed at SQL Call Site 1 in the code listing.