Hibernate Профилирование - PullRequest
       4

Hibernate Профилирование

0 голосов
/ 07 декабря 2011

Есть ли хороший надежный способ определить, откуда запрос Hibernate получает свои данные (например, кэш sesison или кэш второго уровня или из базы данных)? Если я настраиваю Hibernate со следующими свойствами:

 <prop key="hibernate.show_sql">true</prop>
 <prop key="hibernate.format_sql">true</prop>

Я получаю тонну информации о выбранных выборках (хотя я не знаю, откуда они извлекаются). Поскольку это приложение Spring MVC, и все наши запросы обрабатываются с помощью контроллеров Spring, я создал следующий перехватчик:

public class ProfilingInterceptor implements HandlerInterceptor {

  @Autowired private SessionFactory sessionFactory;
  private static final String STATS = "hibernateStats";
  private static final String START_TIME = "startTime";
  private static final Logger LOGGER = Logger.getLogger(ProfilingInterceptor.class);

  @Override public boolean preHandle(HttpServletRequest request,
                                     HttpServletResponse response,
                                     Object handler) throws Exception {
    request.getSession().setAttribute(START_TIME, System.currentTimeMillis());
    request.getSession().setAttributes(STATS, new HibernateStatistics(sessionFactory.getStatistics());
    return true;
  }

  @Override public boolean postHandle(HttpServletRequest request,
                                     HttpServletResponse response,
                                     Object handler) throws Exception {
    HibernateStatistics stats = (HibernateStatistics) 
                                request.getSession().getAttribute("STATS");
    stats.update(sessionFactory.getStatistics());
    request.getSession().setAttribute(STATS, new HibernateStatistics(sessionFactory.getStatistics()));
    LOGGER.debug(stats);
  }

  @Override public boolean postHandle(HttpServletRequest request,
                                     HttpServletResponse response,
                                     Object handler,
                                     Exception ex) throws Exception {
    long startTime = (Long) request.getSession().getAttribute(START_TIME);
    long currentTime = System.currentTimeMillis();
    request.getSession().setAttribute(START_TIME, null);
    long totalTime = currentTime - startTime;
    LOGGER.debug("URI: " request.getRequestURI() + " Method: " 
                 + request.getMethod() + " took " + totalTime + "ms.");
    HibernateStatistics stats = (HibernateStatistics) 
                                 request.getSession().getAttribute(STATS);
    stats.update(sessionFactory.getStatistics());
    LOGGER.debug(stats);
  }
}

Вот как выглядит объект HibernateStatistics (это внутренний класс):

private static final class HibernateStatistics implements Serializable {
  private static final long serialVersionUID = 1L;
  private long queryExecutions = 0;
  private long transactions = 0;
  private long entityLoads = 0;
  private long connects = 0;
  private long time = 0;
  private double secondLevelHits = 0;
  private double secondLevelMisses = 0;
  private double queryHits = 0;
  private double queryMisses = 0;

  public HibernateStatistics(Statistics stats) {
    synchronized(stats) {
      queryExecutions = -stats.getQueryExecutionCount();
      transactions = -stats.getTransactionCount();
      entityLoads = -stats.getEntityLoadCount();
      connects = -stats.getConnectCount();
      secondLevelHits = -stats.getSecondLevelCacheHitCount();
      secondLevelMisses = -stats.getSecondLevelCacheMissCount();
      queryHits = -stats.getQueryCacheHitCount();
      queryMisses = -stats.getQueryCacheMissCount();
      time = -System.currentTimeMillis();
    }
  }

  public void update(Statistics stats) {
    synchronized(stats) {
      queryExecutions += stats.getQueryExecutionCount();
      transactions += stats.getTransactionCount();
      entityLoads += stats.getEntityLoadCount();
      connects += stats.getConnectCount();
      secondLevelHits += stats.getSecondLevelCacheHitCount();
      secondLevelMisses += stats.getSecondLevelCacheMissCount();
      queryHits += stats.getQueryCacheHitCount();
      queryMisses += stats.getQueryCacheMissCount();
      time += System.currentTimeMillis();
    }
  }

  @Override
  public String toString() {
    return "Stats"
    + "[ queries=" + queryExecutions
    + ", xactions=" + transactions
    + ", loads=" + entityLoads
    + ", connects=" + connects
    + ", queryCacheHits=" + queryHits
    + ", secondLevelCacheHits=" + secondLevelHits
    + ", time=" + time + " ]";
  }
}

Я использовал однопоточные тесты, чтобы найти некоторые ситуации, когда у нас может быть проблема с запросом N + 1 в коде, но на этом этапе наше количество соединений и транзакций выглядит хорошо на всех наших страницах.

Теперь мне нужен хороший способ определить, насколько эффективен наш второй уровень и кеширование запросов. Проблема заключается в том, что HibernateStatistics не является потокобезопасным. Поэтому, когда мы пытаемся выполнить многопоточность, я вижу странные числа для этих значений. Это так же просто, как собрать статистику и отобразить ее на странице для дальнейшего анализа?

1 Ответ

2 голосов
/ 07 декабря 2011

Почему в запросах передается статистика? Предполагая, что вы настроили SessionFactory как singleton, sessionFactory.getStatistics () всегда будет возвращать один и тот же объект статистики, где бы и сколько раз вы ни вызывали его в приложении. Вам не нужно использовать класс HibernateStatistics для регистрации статистики. Вы можете просто реализовать статический метод util, который может регистрировать статистику. Фабрика сессий просто накапливает статистику с момента ее инициализации.

I выборки находятся в журнале, что означает, что они загружаются из БД. Если это из кэша сеанса / 2-го уровня, запросы не регистрируются в спящем режиме. Единственный надежный способ проверить производительность кеша - отслеживать соотношение попаданий и промахов в статистике кеша. Вы также можете включить статистику на уровне объекта. Отметьте здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...