Using NHibernate Profiler

NHibernate Profiler from Hibernating Rhinos is a powerful tool for analyzing, visualizing what is happening inside your NHibernate application, and for discovering issues you may have. In this recipe, we will show you how to get up and running with NHibernate Profiler.

Getting ready

Download NHibernate Profiler from http://nhprof.com and unzip it. As it is a commercial product, you will also need a license file. You can request a 30-day trial license from the NHProf website.

Using our Eg.Core model from Chapter 2, Models and Mapping, set up a new NHibernate console application with log4net, just as we did in Chapter 1, The Configuration and Schema.

How to do it...

  1. Install NHibernateProfiler.Appender using the NuGet Package Manager Console by executing the following command:
    Install-Package NHibernateProfiler.Appender
    
  2. In the session-factory element of App.config, set the generate_statistics property to true.
  3. Add the following code to your Main method:
    HibernatingRhinos.Profiler.Appender.
    NHibernate.NHibernateProfiler.Initialize();
    
    var nhConfig = new Configuration().Configure();
    var sessionFactory = nhConfig.BuildSessionFactory();
    
    using (var session = sessionFactory.OpenSession())
    {
      var books = from b in session.Query<Book>()
                  where b.Author == "Jason Dentler"
                  select b;
    
      foreach (var book in books)
        Console.WriteLine(book.Name);
    }
  4. Run NHProf.exe from the NH Profiler download and activate the license.
  5. Build and run your console application.
  6. Check the NH Profiler. It should look similar to the next screenshot. Note the gray dots, which indicate alerts, next to Session #1 and Recent Statements:
    How to do it...
  7. Select Session #1 from the Sessions list in the top-left pane.
  8. Select a statement from the top-right pane.
  9. Note the SQL statement in the following screenshot:
    How to do it...
  10. Click on See the 1 row(s) resulting from this statement.
  11. Enter your database connection string in the field provided and click on OK.
  12. Close the query results window.
  13. Switch to the Alerts tab and note the alert message, which reads Use of implicit transaction is discouraged.
  14. Click on the Read more link for more information and suggested solutions to this particular issue.
  15. Switch to the Stack Trace tab, as shown in the next screenshot:
    How to do it...
  16. Double-click on the NHProfTest.NHProfTest.Program.Main stack frame to jump to that location inside Visual Studio.
  17. Using the following code, wrap the foreach loop in a transaction and commit the transaction:
    using (var tx = session.BeginTransaction())
    {
      foreach (var book in books)
        Console.WriteLine(book.Name);
      tx.Commit();
    }
  18. In NHibernate Profiler, right-click on Sessions in the top-left pane and select Clear All Sessions.
  19. Build and run your application.
  20. Check NHibernate Profiler for alerts.

How it works...

NHibernate Profiler uses a custom log4net appender to capture data about NHibernate activities inside your application and transmits that data to the NHibernate Profiler application.

As we learned in Chapter 2, Models and Mapping, setting generate_statistics allows NHibernate to capture many key data points. These statistics are displayed in the lower left-hand side of the pane of NHibernate Profiler.

We initialize NHibernate Profiler with a call to NHibernateProfiler.Initialize(). For best results, do this when your application starts, just after you have configured log4net.

There's more...

NHibernate Profiler also supports offline and remote profiling, as well as command-line options for use with build scripts and continuous integration systems.

In addition to NHibernate warnings and errors, NHibernate Profiler alerts us to more than 12 common misuses of NHibernate. Some of them are:

  • Too many joins: A query contains a large number of joins. When executed in a batch, multiple simple queries with only a few joins often perform better than a complex query with many joins. This alert can also indicate unexpected Cartesian products.
  • Column type mismatch: When the type of parameter in a query is not an exact match for the table's column type in the database, this can cause several implicit conversion issues, which in turn lead to performance issues (for example, ignored indexes) and conversion overflow issues.
  • Different parameter sizes result in inefficient query plan cache usage: NHibernate detected two-identical queries with different parameter sizes. Each of these queries will create a query plan. This problem grows exponentially with the size and number of parameters used. Setting prepare_sql to true allows NHibernate to generate queries with consistent parameter sizes.
  • Don't query from the view: This alert is raised when the profiler detects that a query was executed inside a view in an MVC application. Issuing queries in an MVC view is a bad practice for several reasons.
  • Ends with queries (like '%...') will force the database to scan the full table: The database cannot use an index for this kind of query and it is, hence, forced to perform a full table scan, inspecting each of the values in the database for a match.
  • Excessive number of rows: In nearly all cases, this indicates a poorly designed query or a bug.
  • Large number of individual writes: This indicates a failure to batch writes, either because adonet.batch_size is not set or possibly because an Identity-type POID generator is used, which effectively disables batching.
  • More than one session-per-request: It is usually recommended to use one session-per-request.
  • Queries and data bindings should not mix: This alert is raised whenever the profiler detects that a query has been generated because of a data binding operation.
  • Query on unindexed column: A query on an unindexed column forces the database to perform a table scan.
  • Select N+1: This alert indicates a particular type of anti-pattern where, typically, we load and enumerate a list of parent objects and lazy-load their children as we move through the list. Instead, we should eagerly fetch those children before enumerating the list.
  • Superfluous updates use inverse="true": NHibernate Profiler detected an unnecessary update statement from a bi-directional one-to-many relationship. Use inverse="true" on the many side (list, bag, set, and so on) of the relationship to avoid this.
  • Too many cache calls per session: This alert is targeted particularly at applications using a distributed (remote) second-level cache. By design, NHibernate does not batch calls to the cache, which can easily lead to hundreds of slow remote calls. It can also indicate an over reliance on the second-level cache, whether remote or local.
  • Too many database calls per session: This usually indicates a misuse of the database, such as querying inside a loop, a select N+1 bug, or an excessive number of writes.
  • Too many expressions per where clause: Having too many expressions inside the where statement can lead to poor performance, especially when the application grows and has a big data set.
  • Too many nested select statements: The query has many nested SELECT statements, which makes the SQL hard to follow and more resource-intensive for the database to parse and execute.
  • Too many tables in selected statement: The more tables there are in a query, the more work the database has to do, irrespective of whether this is achieved via sub selects, joins, or nested queries.
  • Too many where clauses in statement: Having too many where statements can lead to poor performance, especially when the application grows and has a big data set.
  • Transaction disposed without explicit rollback or commit: If no action is taken, transactions will rollback when disposed. However, this often indicates a missing commit rather than a desire to rollback the transaction.
  • Unbounded result set: NHibernate Profiler detected a query without a row limit. When the application is moved to production, these queries may return very large result sets, thus leading to catastrophic performance issues. You should limit the maximum number of rows returned by each query as an insurance against these issues.
  • Use of implicit transactions is discouraged: Nearly all session activity should happen inside an NHibernate transaction.
  • Using a single session on multiple threads is likely a bug: A session should only be used by one thread at a time. Sharing a session across threads is usually a bug, not an explicit design choice, which will require proper locking.

See also

  • Configuring NHibernate with App.config
  • Configure log4net logging
  • Profiling NHibernate with Glimpse
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.137.7