/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.stat.internal;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.hibernate.stat.QueryStatistics;

import org.jboss.logging.Logger;

Query statistics (HQL and SQL)

Note that for a cached query, the cache miss is equals to the db count
Author:Alex Snaps
/** * Query statistics (HQL and SQL) * <p/> * Note that for a cached query, the cache miss is equals to the db count * * @author Alex Snaps */
public class QueryStatisticsImpl implements QueryStatistics { private static final Logger log = Logger.getLogger( QueryStatisticsImpl.class ); private final String query; private final LongAdder cacheHitCount = new LongAdder(); private final LongAdder cacheMissCount = new LongAdder(); private final LongAdder cachePutCount = new LongAdder(); private final LongAdder executionCount = new LongAdder(); private final LongAdder executionRowCount = new LongAdder(); private final AtomicLong executionMaxTime = new AtomicLong(); private final AtomicLong executionMinTime = new AtomicLong(Long.MAX_VALUE); private final AtomicLong totalExecutionTime = new AtomicLong(); private final Lock readLock; private final Lock writeLock; QueryStatisticsImpl(String query) { this.query = query; ReadWriteLock lock = new ReentrantReadWriteLock(); this.readLock = lock.readLock(); this.writeLock = lock.writeLock(); }
queries executed to the DB
/** * queries executed to the DB */
public long getExecutionCount() { return executionCount.sum(); }
Queries retrieved successfully from the cache
/** * Queries retrieved successfully from the cache */
public long getCacheHitCount() { return cacheHitCount.sum(); } public long getCachePutCount() { return cachePutCount.sum(); } public long getCacheMissCount() { return cacheMissCount.sum(); }
Number of lines returned by all the executions of this query (from DB) For now, Query.iterate() and org.hibernate.Query#scroll()() do not fill this statistic
Returns:The number of rows cumulatively returned by the given query; iterate and scroll queries do not effect this total as their number of returned rows is not known at execution time.
/** * Number of lines returned by all the executions of this query (from DB) * For now, {@link org.hibernate.Query#iterate()} * and {@link org.hibernate.Query#scroll()()} do not fill this statistic * * @return The number of rows cumulatively returned by the given query; iterate * and scroll queries do not effect this total as their number of returned rows * is not known at execution time. */
public long getExecutionRowCount() { return executionRowCount.sum(); }
average time in ms taken by the execution of this query onto the DB
/** * average time in ms taken by the execution of this query onto the DB */
public long getExecutionAvgTime() { return (long) getExecutionAvgTimeAsDouble(); }
average time in ms as double taken by the execution of this query onto the DB
/** * average time in ms as double taken by the execution of this query onto the DB */
public double getExecutionAvgTimeAsDouble() { // We write lock here to be sure that we always calculate the average time // with all updates from the executed applied: executionCount and totalExecutionTime // both used in the calculation writeLock.lock(); try { double avgExecutionTime = 0; final long ec = executionCount.sum(); if ( ec > 0 ) { avgExecutionTime = totalExecutionTime.get() / (double) ec; } return avgExecutionTime; } finally { writeLock.unlock(); } }
max time in ms taken by the execution of this query onto the DB
/** * max time in ms taken by the execution of this query onto the DB */
public long getExecutionMaxTime() { return executionMaxTime.get(); }
min time in ms taken by the execution of this query onto the DB
/** * min time in ms taken by the execution of this query onto the DB */
public long getExecutionMinTime() { return executionMinTime.get(); }
total time in ms taken by the execution of this query onto the DB
/** * total time in ms taken by the execution of this query onto the DB */
public long getExecutionTotalTime() { return totalExecutionTime.get(); }
add statistics report of a DB query
Params:
  • rows – rows count returned
  • time – time taken
/** * add statistics report of a DB query * * @param rows rows count returned * @param time time taken */
void executed(long rows, long time) { log.tracef( "QueryStatistics - query executed : %s", query ); // read lock is enough, concurrent updates are supported by the underlying type AtomicLong // this only guards executed(long, long) to be called, when another thread is executing getExecutionAvgTime() readLock.lock(); try { // Less chances for a context switch for ( long old = executionMinTime.get(); (time < old) && !executionMinTime.compareAndSet(old, time); old = executionMinTime.get() ) {} for ( long old = executionMaxTime.get(); (time > old) && !executionMaxTime.compareAndSet(old, time); old = executionMaxTime.get() ) {} executionCount.increment(); executionRowCount.add( rows ); totalExecutionTime.addAndGet( time ); } finally { readLock.unlock(); } } void incrementCacheHitCount() { log.tracef( "QueryStatistics - cache hit : %s", query ); cacheHitCount.increment(); } void incrementCacheMissCount() { log.tracef( "QueryStatistics - cache miss : %s", query ); cacheMissCount.increment(); } void incrementCachePutCount() { log.tracef( "QueryStatistics - cache put : %s", query ); cachePutCount.increment(); } public String toString() { return "QueryStatistics" + "[query=" + query + ",cacheHitCount=" + this.cacheHitCount + ",cacheMissCount=" + this.cacheMissCount + ",cachePutCount=" + this.cachePutCount + ",executionCount=" + this.executionCount + ",executionRowCount=" + this.executionRowCount + ",executionAvgTime=" + this.getExecutionAvgTime() + ",executionMaxTime=" + this.executionMaxTime + ",executionMinTime=" + this.executionMinTime + ']'; } }