论坛首页 Java版 Hibernate

利用Hibernate3架构一个跨数据库的SQL语句性能分析器

浏览 2719 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2005-10-03
引用

Optimization is not much use without monitoring and access to performance numbers.


在Hibernate3 Reference 20.6节中,提到了Hibernate3可以利用JMX收集系统运行时的一些数据,从而给出一些可供优化系统性能的数据。

当是最简单的方式莫过于直接使用 SessionFactory.getStatistics() 来获取这些统计信息,当然前提是你要在hibernate的配置文件中把 hibernate.generate_statistics 设为 true。

写一个定时任务:

[code:1]
        Statistics stats = sessionFactory.getStatistics();

        //total statistics
        stats.logSummary();

        String[] clazz = stats.getEntityNames();
       
        //entity statistics
        if (clazz != null && clazz.length > 0)
        {
            for (int i=0;i<clazz.length;i++)
            {
                EntityStatistics entityStats = stats.getEntityStatistics(clazz[i]);
               
                logger.info(clazz[i]);
               
                logger.info("inserted : " + entityStats.getInsertCount());
               
                logger.info("updated : " + entityStats.getUpdateCount());
               
                logger.info("deleted  : " + entityStats.getDeleteCount());
               
                logger.info("loaded   : " + entityStats.getLoadCount());
            }
        }
       
        String[] queries = stats.getQueries();
       
        //queries statistics
        if (queries != null && queries.length > 0)
        {
            for (int i=0;i<queries.length;i++)
            {
                QueryStatistics queryStats = stats.getQueryStatistics( queries[i] );
               
                logger.info(queries[i]);
               
                logger.info("ExecutionAvgTime  : " + queryStats.getExecutionAvgTime() );
               
                logger.info("ExecutionMinTime   : " + queryStats.getExecutionMinTime() );
               
                logger.info("ExecutionMaxTime  : " + queryStats.getExecutionMaxTime() );
               
                logger.info("ExecutionCount      : " + queryStats.getExecutionCount() );
               
                logger.info("ExecutionRowCount : " + queryStats.getExecutionRowCount() );
            }
        }
       
        //clear
        stats.clear();
[/code:1]

把你的log4j配置到这个定时器,不过 logger 必须是:

[code:1]
private static final Log logger = LogFactory.getLog("org.hibernate.stat.StatisticsImpl");
[/code:1]

否则,你不能看到 stats.logSummary() 的统计信息,当然,你也可以用自己的log记录stats.toString(),结果一样,只不过格式不同而已。

然后,每隔一段时间你就会得到一个统计报告,里面有二级缓存的使用情况,访问数据库的次数,执行事务的次数,每个实体的增、删、改、查次数,每个运行过的HQL的执行时间。

扩展:

默认的Hibernate3只能统计HQL和native SQL,无法统计对象载入及由此产生的Fetch的语句的性能,以及Criteria查询API所产生的语句的性能。

Gavin解释了理由:http://forum.hibernate.org/viewtopic.php?t=948329

由此可见Hibernate Team对于由他们的程序所生成的SQL语句的性能多么自信,呵呵

但是我觉得,如果仅仅是为了系统架构的考虑,和对Hibernate的信心,还不足以使我放弃统计其他的SQL语句。所以,修改了Hibernate3的代码:

org.hibernate.loader.Loader :

[code:1]
protected String getQueryIdentifier()
{
     return null;
}
[/code:1]

to

[code:1]
protected String getQueryIdentifier()
{
     return getSQLString();
}
[/code:1]

因为Loader本来只在载入对象时运行,而运行HQL是由继承它的子类完成,而Hibernate Team不认为需要统计由此产生的SQL语句,所以直接返回空,使得统计分析器忽略这些SQL语句。而这个修改,使得所有的SQL以自己的实际内容作为标识,从而使得只要是hibernate运行过得SQL语句均会被统计到。

结束语:

Hibernate3提供这样一个功能,对于系统调优非常有帮助,在系统测试阶段,不用考虑由此统计工具带来的性能问题,可以详尽了解SQL语句的运行情况,从而视情况做优化。正式系统中不建议使用,因为统计本身会消耗较大的内存,如果短间隔的clear统计信息,得到的数据又没有说服力。
   
论坛首页 Java版 Hibernate

跳转论坛:
JavaEye推荐