Retrieving Objects Strategies for solving the “n+1 selects” problem
Retrieving objects <ul><li>We can get objects out of the database with </li></ul><ul><ul><li>retrieval by identifier , whe...
Retrieval by identifier <ul><li>Simple strategy, we use  get()  or  load() : </li></ul><ul><li>If  load()  doesn't find th...
Hibernate Fetching Strategies <ul><li>Fetching strategies are used to minimize database access </li></ul><ul><li>when load...
Metadata fetching strategies for single-ended associations <ul><li>Lazy fetching for  many-to-one  and  one-to-one  associ...
Metadata fetching strategies for collections <ul><li>Collections of entity references or of values </li></ul><ul><ul><li>b...
Initializing lazy associations <ul><li>We can explicitly initialize lazy loaded objects and collections: </li></ul><ul><li...
The  n+1 selects  problem <ul><li>We usually map all associations as lazy, now if we load  Item s: </li></ul><ul><li>The  ...
Solving the  n+1 selects  problem <ul><li>We can use batch fetching (n/10 + 1 selects): </li></ul><ul><li>We can use (glob...
Solving the  n+1 selects  problem <ul><li>Also recommended: take advantage of the second-level cache: </li></ul><ul><li>We...
Upcoming SlideShare
Loading in …5
×

07 Retrieving Objects

627 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
627
On SlideShare
0
From Embeds
0
Number of Embeds
65
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

07 Retrieving Objects

  1. 1. Retrieving Objects Strategies for solving the “n+1 selects” problem
  2. 2. Retrieving objects <ul><li>We can get objects out of the database with </li></ul><ul><ul><li>retrieval by identifier , when the identifier of an object is known </li></ul></ul><ul><ul><li>HQL , a full object-oriented query language </li></ul></ul><ul><ul><li>Criteria Queries , a typesafe way to build complex queries (QBC, QBE) </li></ul></ul><ul><ul><li>Native SQL , with Hibernate mapping from result set to objects </li></ul></ul><ul><ul><li>implicit , by navigating the object graph starting with a persistent object </li></ul></ul><ul><li>All query options can use the </li></ul><ul><li>Hibernate fetching strategies for best performance. </li></ul><ul><li>QBC - Query by critieria </li></ul><ul><li>QBE – Query by Expression </li></ul>
  3. 3. Retrieval by identifier <ul><li>Simple strategy, we use get() or load() : </li></ul><ul><li>If load() doesn't find the object in cache or database, it </li></ul><ul><li>throws an exception, get() will return a null. </li></ul><ul><li>A load() method may return a proxy, without hitting the database. </li></ul>User user = (User) session.get(User.class, userID); User user = (User) session.load(User.class, userID);
  4. 4. Hibernate Fetching Strategies <ul><li>Fetching strategies are used to minimize database access </li></ul><ul><li>when loading a subgraph of the full graph of persistent objects. </li></ul><ul><li>Lazy Fetching </li></ul><ul><ul><li>associated objects or collections will only be loaded when accessed </li></ul></ul><ul><li>Eager Fetching </li></ul><ul><ul><li>associated objects or collections are loaded with the owning object with a single SQL outer-join fetch </li></ul></ul><ul><li>Batch Fetching </li></ul><ul><ul><li>improves lazy fetching by retrieving a &quot;batch&quot; of objects or collections </li></ul></ul>
  5. 5. Metadata fetching strategies for single-ended associations <ul><li>Lazy fetching for many-to-one and one-to-one associations </li></ul><ul><ul><li>the associated (target) class must have (automatic) proxying enabled: </li></ul></ul><ul><li>Eager fetching overrides laziness </li></ul><ul><ul><li>either auto (global configuration setting, default) , true or false can be used: </li></ul></ul><ul><li>Batch fetching is used to set the batch size when lazy loading </li></ul><class name=&quot;Item&quot; lazy=&quot;true&quot; > or <class name=&quot;Item&quot; proxy=&quot;ItemInterface&quot; > <class name=&quot;Bid&quot;> <many-to-one name=&quot;item&quot; class=&quot;Item&quot; outer-join=&quot;true&quot; > <class name=&quot;Item&quot; lazy=&quot;true&quot; batch-size=&quot;9&quot; >
  6. 6. Metadata fetching strategies for collections <ul><li>Collections of entity references or of values </li></ul><ul><ul><li>by default outer-join=&quot;false&quot; and lazy=&quot;false&quot; (two SELECTS) </li></ul></ul><ul><li>Eager and Lazy Fetching has to be enabled for a collection mapping </li></ul><ul><ul><li>only one collection can be outer-joined, lazy and eager don't make sense! </li></ul></ul><ul><li>Eager Fetching for many-to-many is a special case </li></ul><set name=&quot;items&quot; outer-join=&quot;true&quot; > <key column=&quot;CATEGORY_ID&quot;/> <many-to-many column=&quot;ITEM_ID&quot; outer-join=&quot;true&quot; class=&quot;Item&quot;/> </set> <set name=&quot;bids&quot; lazy=&quot;true&quot; > <key column=&quot;ITEM_ID&quot;/> <one-to-many class=&quot;Bid&quot;/> </set> or <set name=&quot;bids&quot; outer-join=&quot;true&quot; > <key column=&quot;ITEM_ID&quot;/> <one-to-many class=&quot;Bid&quot;/> </set>
  7. 7. Initializing lazy associations <ul><li>We can explicitly initialize lazy loaded objects and collections: </li></ul><ul><li>We can also keep the Session open until we accessed </li></ul><ul><li>all lazily loaded associatoins, e.g. while rendering a view! </li></ul><ul><li>This is a question of application architecture. </li></ul>Category cat = (Category) session.get(Category.class, id); Hibernate.initialize( cat.getItems() );
  8. 8. The n+1 selects problem <ul><li>We usually map all associations as lazy, now if we load Item s: </li></ul><ul><li>The bids collection of each Item is not initialized: </li></ul><ul><li>We execute n selects for n collections of Bid s! </li></ul>Iterator items = session.createCriteria(Item.class) .add( Expression.eq(&quot;item.seller&quot;, user) ) .list() .iterator(); List maxAmounts = new ArrayList(); for ( ; items.hasNext(); ) { Item item = (Item) items.next(); float maxAmount = 0.0f; for ( Iterator bids = item.getBids() .iterator(); bids.hasNext(); ) { Bid bid = (Bid) bids.next(); if ( bid.getAmount() > maxAmount ) maxAmount = bid.getAmount(); } maxAmounts.add( new MaxAmount( item.getId(), maxAmount ) ); }
  9. 9. Solving the n+1 selects problem <ul><li>We can use batch fetching (n/10 + 1 selects): </li></ul><ul><li>We can use (global) eager fetching (does not affect HQL queries): </li></ul><ul><li>Recommended: use dynamic association fetching in queries: </li></ul>List results = session.createCriteria(Item.class) .add( Expression.eq(&quot;item.seller&quot;, user) ) .setFetchMode(&quot;bids&quot;, FetchMode.EAGER) .list(); Iterator items = new HashSet( results ) .iterator(); // make results distinct <set name=&quot;bids&quot; lazy=&quot;true&quot; inverse=&quot;true&quot; batch-size=&quot;10&quot; > <set name=&quot;bids&quot; lazy=&quot;true&quot; inverse=&quot;true&quot; outer-join=&quot;true&quot; > List results = session.createQuery( select i from Item i fetch join i.bids where i.seller = :user ).list(); Iterator items = new HashSet( results ) .iterator(); // make results distinct
  10. 10. Solving the n+1 selects problem <ul><li>Also recommended: take advantage of the second-level cache: </li></ul><ul><li>We do not issue any recursive selects for the subcategories, because they are all read from the cache! </li></ul>Query categoryByName = session.createQuery(&quot;from Category c where c.name like :name&quot;); categoryByName.setString(&quot;name&quot;, categoryNamePattern); List categories = categoryByName. list() ; // SQL: // select ID, NAME, PARENT from CATEGORY where NAME like ?

×