HHH-14632 - Call statistics.queryPlanCacheHit and statistics.queryPlanCacheMiss for FilterQueryPlan and NativeSQLQueryPlan

This commit is contained in:
Vlad Mihalcea 2021-05-24 11:30:59 +03:00 committed by Christian Beikov
parent 7570f39d10
commit cea044ec69
5 changed files with 99 additions and 9 deletions

View File

@ -200,6 +200,8 @@ public class QueryPlanCache implements Serializable {
Map<String,Filter> enabledFilters) throws QueryException, MappingException { Map<String,Filter> enabledFilters) throws QueryException, MappingException {
final FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters ); final FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
FilterQueryPlan value = (FilterQueryPlan) queryPlanCache.get( key ); FilterQueryPlan value = (FilterQueryPlan) queryPlanCache.get( key );
final StatisticsImplementor statistics = factory.getStatistics();
boolean stats = statistics.isStatisticsEnabled();
if ( value == null ) { if ( value == null ) {
LOG.tracev( LOG.tracev(
"Unable to locate collection-filter query plan in cache; generating ({0} : {1} )", "Unable to locate collection-filter query plan in cache; generating ({0} : {1} )",
@ -207,10 +209,17 @@ public class QueryPlanCache implements Serializable {
filterString filterString
); );
value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory ); value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory );
if ( stats ) {
statistics.queryPlanCacheMiss( key.query );
}
queryPlanCache.putIfAbsent( key, value ); queryPlanCache.putIfAbsent( key, value );
} }
else { else {
LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString ); LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString );
if ( stats ) {
statistics.queryPlanCacheHit( key.query );
}
} }
return value; return value;
} }
@ -228,13 +237,22 @@ public class QueryPlanCache implements Serializable {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public NativeSQLQueryPlan getNativeSQLQueryPlan(final NativeSQLQuerySpecification spec) { public NativeSQLQueryPlan getNativeSQLQueryPlan(final NativeSQLQuerySpecification spec) {
NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec ); NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec );
final StatisticsImplementor statistics = factory.getStatistics();
boolean stats = statistics.isStatisticsEnabled();
if ( value == null ) { if ( value == null ) {
LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() ); LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() );
value = nativeQueryInterpreter.createQueryPlan( spec, factory ); value = nativeQueryInterpreter.createQueryPlan( spec, factory );
if ( stats ) {
statistics.queryPlanCacheMiss( spec.getQueryString() );
}
queryPlanCache.putIfAbsent( spec, value ); queryPlanCache.putIfAbsent( spec, value );
} }
else { else {
LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() ); LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() );
if ( stats ) {
statistics.queryPlanCacheHit( spec.getQueryString() );
}
} }
return value; return value;
} }

View File

@ -202,6 +202,10 @@ public class QueryStatisticsImpl implements QueryStatistics {
planCacheHitCount.increment(); planCacheHitCount.increment();
} }
void incrementPlanCacheMissCount() {
planCacheMissCount.increment();
}
public String toString() { public String toString() {
return "QueryStatistics" return "QueryStatistics"
+ "[query=" + query + "[query=" + query

View File

@ -805,11 +805,20 @@ public class StatisticsImpl implements StatisticsImplementor, Service, Manageabl
} }
@Override @Override
public void queryPlanCacheHit(String hql) { public void queryPlanCacheHit(String query) {
queryPlanCacheHitCount.increment(); queryPlanCacheHitCount.increment();
if ( hql != null ) { if ( query != null ) {
getQueryStatistics( hql ).incrementPlanCacheHitCount(); getQueryStatistics( query ).incrementPlanCacheHitCount();
}
}
@Override
public void queryPlanCacheMiss(String query) {
queryPlanCacheMissCount.increment();
if ( query != null ) {
getQueryStatistics( query ).incrementPlanCacheMissCount();
} }
} }

View File

@ -251,9 +251,18 @@ public interface StatisticsImplementor extends Statistics, Service {
/** /**
* Callback indicating a get from the query plan cache resulted in a hit. * Callback indicating a get from the query plan cache resulted in a hit.
* *
* @param hql The query * @param query The query
*/ */
default void queryPlanCacheHit(String hql) { default void queryPlanCacheHit(String query) {
//For backward compatibility
}
/**
* Callback indicating a get from the query plan cache resulted in a miss.
*
* @param query The query
*/
default void queryPlanCacheMiss(String query) {
//For backward compatibility //For backward compatibility
} }

View File

@ -14,6 +14,7 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.LockModeType; import javax.persistence.LockModeType;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Tuple; import javax.persistence.Tuple;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
@ -150,7 +151,7 @@ public class QueryPlanCacheStatisticsTest extends BaseEntityManagerFunctionalTes
assertEquals( 5, employees.size() ); assertEquals( 5, employees.size() );
//The miss count is still 1, as no we got the query plan from the cache //The miss count is still 1, as now we got the query plan from the cache
assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//And the cache hit count increases. //And the cache hit count increases.
assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); assertEquals( 1, statistics.getQueryPlanCacheHitCount() );
@ -164,7 +165,55 @@ public class QueryPlanCacheStatisticsTest extends BaseEntityManagerFunctionalTes
assertEquals( 5, employees.size() ); assertEquals( 5, employees.size() );
//The miss count is still 1, as no we got the query plan from the cache //The miss count is still 1, as now we got the query plan from the cache
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//And the cache hit count increases.
assertEquals( 2, statistics.getQueryPlanCacheHitCount() );
} );
}
@Test
@TestForIssue( jiraKey = "HHH-14632" )
public void testCreateNativeQueryHitCount() {
statistics.clear();
doInJPA( this::entityManagerFactory, entityManager -> {
List<Employee> employees = entityManager.createNativeQuery(
"select * from employee e", Employee.class )
.getResultList();
assertEquals( 5, employees.size() );
//First time, we get a cache miss, so the query is compiled
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//The hit count should be 0 as we don't need to go to the cache after we already compiled the query
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
List<Employee> employees = entityManager.createNativeQuery(
"select * from employee e", Employee.class )
.getResultList();
assertEquals( 5, employees.size() );
//The miss count is still 1, as now we got the query plan from the cache
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//And the cache hit count increases.
assertEquals( 1, statistics.getQueryPlanCacheHitCount() );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
List<Employee> employees = entityManager.createNativeQuery(
"select * from employee e", Employee.class )
.getResultList();
assertEquals( 5, employees.size() );
//The miss count is still 1, as now we got the query plan from the cache
assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//And the cache hit count increases. //And the cache hit count increases.
assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); assertEquals( 2, statistics.getQueryPlanCacheHitCount() );
@ -232,7 +281,7 @@ public class QueryPlanCacheStatisticsTest extends BaseEntityManagerFunctionalTes
assertEquals( 5, employees.size() ); assertEquals( 5, employees.size() );
//The miss count is still 1, as no we got the query plan from the cache //The miss count is still 1, as now we got the query plan from the cache
assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//And the cache hit count increases. //And the cache hit count increases.
assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); assertEquals( 1, statistics.getQueryPlanCacheHitCount() );
@ -246,7 +295,7 @@ public class QueryPlanCacheStatisticsTest extends BaseEntityManagerFunctionalTes
assertEquals( 5, employees.size() ); assertEquals( 5, employees.size() );
//The miss count is still 1, as no we got the query plan from the cache //The miss count is still 1, as now we got the query plan from the cache
assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
//And the cache hit count increases. //And the cache hit count increases.
assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); assertEquals( 2, statistics.getQueryPlanCacheHitCount() );
@ -292,6 +341,7 @@ public class QueryPlanCacheStatisticsTest extends BaseEntityManagerFunctionalTes
} }
@Entity(name = "Employee") @Entity(name = "Employee")
@Table(name = "employee")
@NamedQuery( @NamedQuery(
name = "find_employee_by_name", name = "find_employee_by_name",
query = "select e from Employee e where e.name = :name" query = "select e from Employee e where e.name = :name"