Wednesday, October 28, 2009
NHibernate Optimization - Part 2 - Data Access Object (DAO)
In the first post on NHibernate Optimization, mapping file configuration was discussed. This post will focus on code optimization in data access objects (DAOs).
Load objects by ID.
Object should be loaded by ID whenever possible to benefit from first-level cache (session cache). Whenever an object is saved or loaded it is added to NHibernate's first-level cache with the ID as the key. As a reminder when NHibernate loads an object, it first looks in the first-level cache, then query cache, followed by second-level cache and finally SQL is executed. Therefore, loading an object by ID will be very quick if it is already in first-level cache.
Sometimes the UI layer needs to request an object with a business key rather than a surrogate key. In this case, a thread-safe Dictionary with key=business key and value=surrogate key should be considered. The UI layer requests the object by business key from the service layer. The service layer finds the surrogate key in the Dictionary and uses it to query the DAO. This is a little extra work, but can reap appreciable performance benefits.
Use HQL, DTOs, and/or hand-coded ADO.NET in bottlenecks.
Oftentimes the UI layer presents a screen that summarizes the state of many different objects, which can force many separate and expensive database calls that return much more data that is actually necessary. A good way to optimize this is to use HQL or hand-coded ADO.NET to SELECT only the required data, using aggregate functions if necessary, and return the data in a non-hibernate mapped data transfer object (DTO).
This post scratched the surface of code optimizations in the data access layer. Please stand by for upcoming code optimization recommendations.
Load objects by ID.
Object should be loaded by ID whenever possible to benefit from first-level cache (session cache). Whenever an object is saved or loaded it is added to NHibernate's first-level cache with the ID as the key. As a reminder when NHibernate loads an object, it first looks in the first-level cache, then query cache, followed by second-level cache and finally SQL is executed. Therefore, loading an object by ID will be very quick if it is already in first-level cache.
Sometimes the UI layer needs to request an object with a business key rather than a surrogate key. In this case, a thread-safe Dictionary with key=business key and value=surrogate key should be considered. The UI layer requests the object by business key from the service layer. The service layer finds the surrogate key in the Dictionary and uses it to query the DAO. This is a little extra work, but can reap appreciable performance benefits.
Use HQL, DTOs, and/or hand-coded ADO.NET in bottlenecks.
Oftentimes the UI layer presents a screen that summarizes the state of many different objects, which can force many separate and expensive database calls that return much more data that is actually necessary. A good way to optimize this is to use HQL or hand-coded ADO.NET to SELECT only the required data, using aggregate functions if necessary, and return the data in a non-hibernate mapped data transfer object (DTO).
This post scratched the surface of code optimizations in the data access layer. Please stand by for upcoming code optimization recommendations.
Labels: .Net, NHibernate
Monday, October 26, 2009
NHibernate Optimization - Part 1 - Mapping Files
NHibernate is a powerful object/relational persistence and query service that has deep market penetration in the Java space and is rapidly gaining acceptance in the .Net community. NHibernate is particular beneficial to domain-driven projects as developers can focus on good OO design and have the database automatically generated from the domain model. Since developers are focused on classes and not tables, performance can suffer because little thought is given to how SQL is generated and executed. This is the first post in a series that will focus on strategies to monitor performance, best practices, and optimizing N/Hibernate code.
The Problem
Improper data access code and/or hibernate mapping files can cause NHibernate to execute inefficient queries, execute the same queries over and over, and/or retrieve much more data than needed. The three main areas of concern when dealing with Nhibernate performance are the mapping files, data access objects (DAOs), and monitoring/profiling tools.
Mapping file optimization
Improper fetch strategies are the most common mistakes in Nhibernate mapping files. Many times developers simply copy and paste an existing mapping file and just change the table and column names without giving any thought to fetching strategies used. As a general rule, lazy associations should be used by default because no matter what fetching strategy is used, non-lazy relationships will be fully loaded into memory executing SQL queries if necessary.
The Problem
Improper data access code and/or hibernate mapping files can cause NHibernate to execute inefficient queries, execute the same queries over and over, and/or retrieve much more data than needed. The three main areas of concern when dealing with Nhibernate performance are the mapping files, data access objects (DAOs), and monitoring/profiling tools.
Mapping file optimization
Improper fetch strategies are the most common mistakes in Nhibernate mapping files. Many times developers simply copy and paste an existing mapping file and just change the table and column names without giving any thought to fetching strategies used. As a general rule, lazy associations should be used by default because no matter what fetching strategy is used, non-lazy relationships will be fully loaded into memory executing SQL queries if necessary.
The Nhibernate developer should read and understand the fetching strategy section of the reference documentation. Batch fetching and subselect fetching can significantly reduce the number of SQL queries executed.
Another mapping element that can speed up the NHibernate application is second-level caching. A good idea for all applications is to enable read-only cache on "look-up" data that never changes. Nonstrict-read-write works well for objects that are mostly read and seldom written. More on caching will follow in upcoming posts.
In summary, use lazy associations by default, choose the write fetching strategy, and include second-level caching when appropriate.
Another mapping element that can speed up the NHibernate application is second-level caching. A good idea for all applications is to enable read-only cache on "look-up" data that never changes. Nonstrict-read-write works well for objects that are mostly read and seldom written. More on caching will follow in upcoming posts.
In summary, use lazy associations by default, choose the write fetching strategy, and include second-level caching when appropriate.
Labels: .Net, NHibernate, Performance
Friday, July 24, 2009
TFS - Stop and Start Server
After some failed attempts at stopping and starting servers through third party tasks, I had quick success using the exec command in the TFSBuild.proj:
<PropertyGroup>
<web-site-id>1</web-site-id>
<server-cmd-prefix>C:\Windows\system32\cscript.exe c:\Inetpub\AdminScripts\adsutil.vbs</server-cmd-prefix>
<stop-server-cmd-line>$(server-cmd-prefix) STOP_SERVER W3SVC/$(web-site-id)</stop-server-cmd-line>
<start-server-cmd-line>$(server-cmd-prefix) START_SERVER W3SVC/$(web-site-id)</start-server-cmd-line>
</PropertyGroup>
<Target Name="StopSite">
<Message Text="stopping site..."/>
<Exec Command="$(stop-server-cmd-line)"/>
</Target>
<Target Name="StartSite">
<Message Text="starting site..."/>
<Exec Command="$(start-server-cmd-line)"/>
</Target>
To find the web-site-id, refer to Scott Forsyth's Blog.
Subscribe to Posts [Atom]


