Checked statistics docs

git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@5970 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Christian Bauer 2005-02-28 18:49:16 +00:00
parent 4b13e3544f
commit a308fb5153
2 changed files with 94 additions and 73 deletions

View File

@ -237,9 +237,5 @@ cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() )
</sect1> </sect1>
<para>
TODO: document statistics
</para>
</chapter> </chapter>

View File

@ -1119,129 +1119,154 @@ hibernate.cache.use_structured_entries true]]></programlisting>
<sect1 id="performance-monitoring" revision="1"> <sect1 id="performance-monitoring" revision="1">
<title>Monitoring performance</title> <title>Monitoring performance</title>
<para>Performance and optimization are nothing without monitoring. Without rational and concrete figures,
no good optimization is possible. Hibernate provides a full panel of figures related to Hibernate behaviors.
Hibernate statistics are related to a particular session factory. This makes perfect sense if we consider
the typical application as being build on top of one database / session factory.</para>
<sect2 id="performance-monitoring-sf" revision="1">
<title>Monitoring a session factory</title>
<para> <para>
Session factories publish their metrics through 2 basic ways. The first one use direct access to the Optimization is not much use without monitoring and access to performance numbers.
<literal>SessionFactory</literal> object. The statistics are attached to a session factory through Hibernate provides a full range of figures about its internal operations.
<literal>Statistics</literal> objects and accessed by <literal>sessionFactory.getStatistics()</literal>. Statistics in Hibernate are available per <literal>SessionFactory</literal>.
The second way, a bit more standard, use JMX to publish them through the <literal>StatisticsService</literal>
either one MBean per session factory, either one MBean for all session factories. Here is a minimalistic
code showing both ways (you must have a JMX server available).
</para> </para>
<programlisting><![CDATA[//Register the MBean in your JMX server for a specific session factory
<sect2 id="performance-monitoring-sf" revision="2">
<title>Monitoring a SessionFactory</title>
<para>
You can access <literal>SessionFactory</literal> metrics in two ways.
Your first option is to call <literal>sessionFactory.getStatistics()</literal> and
read or display the <literal>Statistics</literal> yourself.
</para>
<para>
Hibernate can also use JMX to publish metrics if you enable the
<literal>StatisticsService</literal> MBean. You may enable a single MBean for all your
<literal>SessionFactory</literal> or one per factory. See the following code for
minimalistic configuration examples:
</para>
<programlisting><![CDATA[// MBean service registration for a specific SessionFactory
Hashtable tb = new Hashtable(); Hashtable tb = new Hashtable();
tb.put("type", "statistics"); tb.put("type", "statistics");
tb.put("sessionFactory", "myFinancialApp"); tb.put("sessionFactory", "myFinancialApp");
ObjectName on = new ObjectName("hibernate", tb); //the MBean object name ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); //MBean implementation
stats.setSessionFactory(sessionFactory); //the awaited session factory
server.registerMBean(stats, on); //we register the MBean
//And call the MBean the way you want
//or StatisticsService stats = new StatisticsService(); // MBean implementation
stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
//Register the MBean in your JMX server with no specific session factory binding
<programlisting><![CDATA[// MBean service registration for all SessionFactory's
Hashtable tb = new Hashtable(); Hashtable tb = new Hashtable();
tb.put("type", "statistics"); tb.put("type", "statistics");
tb.put("sessionFactory", "all"); tb.put("sessionFactory", "all");
ObjectName on = new ObjectName("hibernate", tb); //the object name ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); //the generic StatisticService
server.registerMBean(stats, on); //we register the MBean]]></programlisting> StatisticsService stats = new StatisticsService(); // MBean implementation
server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
<para> <para>
In the first case, we retrieve and use the MBean directly. In the second one, we must give the JNDI name TODO: This doesn't make sense. In the first case, we retrieve and use the MBean directly. In the second one, we must give
in which the session factory is held before using it. Use the JNDI name in which the session factory is held before using it. Use
<literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal> <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
</para> </para>
<para> <para>
A session factory can be monitored or not. You can (de)activate the monitoring You can (de)activate the monitoring for a <literal>SessionFactory</literal>
</para> </para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
at configuration time: <literal>hibernate.generate_statistics</literal>, default to false at configuration time, set <literal>hibernate.generate_statistics</literal> to <literal>false</literal>
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
at runtime time: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal> at runtime: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
or <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal> or <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para>Statistics can be reset programatically using the <literal>clear()</literal> method. A summary
can be sent to a logger (info level) using the <literal>logSummary()</literal> method.</para> <para>
Statistics can be reset programatically using the <literal>clear()</literal> method.
A summary can be sent to a logger (info level) using the <literal>logSummary()</literal>
method.
</para>
</sect2> </sect2>
<sect2 id="performance-monitoring-metrics" revision="1"> <sect2 id="performance-monitoring-metrics" revision="1">
<title>Metrics</title> <title>Metrics</title>
<para> <para>
Hibernate provides a huge number of metrics, from the very basics to the very specialized ones. Hibernate provides a number of metrics, from very basic to the specialized information
All available counters are described in the <literal>Statistics</literal> interface API. only relevant in certain scenarios. All available counters are described in the
They are basically split into 3 categories: <literal>Statistics</literal> interface API, in three categories:
</para> </para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
metrics related to the general session usage (number of session open, session close, connections retrieved, ...), Metrics related to the general <literal>Session</literal> usage, such as
number of open sessions, retrieved JDBC connections, etc.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
metrics related to the entities, collections, queries, and caches as a whole (aka global metrics), Metrics related to he entities, collections, queries, and caches as a
whole (aka global metrics),
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
detailed metrics related to a particular entity, collection, query or cache region. Detailed metrics related to a particular entity, collection, query or
cache region.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para> <para>
You can find (for example) the cache hit, miss and put ratio of entities, collections For exampl,e you can check the cache hit, miss, and put ratio of entities, collections
and queries, the average time of a query, etc... Beware that the number of milliseconds is subject and queries, and the average time a query needs. Beware that the number of milliseconds
to approximation in Java. Hibernate is tied to the JVM precision: it might lead to a 10 ms approx depending is subject to approximation in Java. Hibernate is tied to the JVM precision, on some
on your platform. platforms this might even only be accurate to 10 seconds.
</para> </para>
<para> <para>
Simple getters are used to access the global metrics (ie not tied to a particular entity, collection, Simple getters are used to access the global metrics (i.e. not tied to a particular entity,
cache region). You access the metrics of a particular entity, collection or cache region through its name, collection, cache region, etc.). You can access the metrics of a particular entity, collection
as shown in the above example, and through its HQL or SQL representation for queries. Please refer to the or cache region through its name, and through its HQL or SQL representation for queries. Please
<literal>Statistics</literal>, <literal>EntityStatistics</literal>, <literal>CollectionStatistics</literal>, refer to the <literal>Statistics</literal>, <literal>EntityStatistics</literal>,
<literal>SecondLevelCacheStatistics</literal> and <literal>QueryStatistics</literal> API for more informations. <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>,
and <literal>QueryStatistics</literal> API Javadoc for more information. The following
code shows a simple example:
</para> </para>
<programlisting><![CDATA[Statistics stats = sf.getStatistics();
double hitRatio = (double) stats.getQueryCacheHitCount() <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
/ ( stats.getQueryCacheHitCount() + stats.getQueryCacheMissCount() );
log.info("Query Hit ratio:" + hitRatio); double queryCacheHitCount = stats.getQueryCacheHitCount();
EntityStatistics entityStats = stats.getEntityStatistics( Cat.class.getName() ); double queryCacheMissCount = stats.getQueryCacheMissCount();
int changes = entityStats.getInsertCount() double queryCacheHitRatio =
+ entityStats.getUpdateCount() + entityStats.getDeleteCount(); queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
log.info(Cat.class.getName() + " changes:" + changes);]]></programlisting>
log.info("Query Hit ratio:" + queryCacheHitRatio);
EntityStatistics entityStats =
stats.getEntityStatistics( Cat.class.getName() );
long changes =
entityStats.getInsertCount()
+ entityStats.getUpdateCount()
+ entityStats.getDeleteCount();
log.info(Cat.class.getName() + " changed " + changes + "times" );]]></programlisting>
<para> <para>
In order to work on all detailed entities, collections, queries and region caches statistics, you can retrieve To work on all entities, collections, queries and region caches, you can retrieve
the list of names of entities, collections, queries and region caches names having metrics. Use <literal>getQueries()</literal>, the list of names of entities, collections, queries and region caches with the
<literal>getEntityNames()</literal>, <literal>getCollectionRoleNames()</literal>, or following methods: <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
<literal>getCollectionRoleNames()</literal>, and
<literal>getSecondLevelCacheRegionNames()</literal>. <literal>getSecondLevelCacheRegionNames()</literal>.
</para> </para>
</sect2> </sect2>
<sect2 id="performance-monitoring-understandingmetrics" revision="1">
<title>Understanding metrics</title>
<para>
You can find interesting informations while looking at metrics. An entity/collection/query with a high cache
miss ratio (cache miss greater than cache hit) should not be cached: the benefit of caching is not significant
for your application and use case.
An entity/collection/query with a cache put much greater than its cache hit should not be cached either: you spend
a lot of resources in caching without efficiently use it.
A session factory having more open sessions than closed ones shows a session leak which must be addressed.
A use case using lots of connections might show a good candidate for a conversion to the session per user
transaction pattern.</para>
</sect2>
</sect1> </sect1>
</chapter> </chapter>