mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1238 - Refactor MetaInfoManager - collect query plan stats, fix collection of stats on UpdateQuery
This commit is contained in:
@@ -34,4 +34,10 @@ public interface ProfileLocation {
|
||||
* Obtain the location description.
|
||||
*/
|
||||
String obtain();
|
||||
|
||||
/**
|
||||
* Return a short version of the location description.
|
||||
*/
|
||||
String shortDescription();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MetaBeanInfo {
|
||||
|
||||
/**
|
||||
* Collect the current query plan statistics return the non-empty statistics.
|
||||
*/
|
||||
List<MetaQueryPlanStatistic> collectQueryPlanStatistics(boolean reset);
|
||||
|
||||
/**
|
||||
* Collect the current query plan statistics return all the statistics (include query plans that haven't had query executions).
|
||||
*/
|
||||
List<MetaQueryPlanStatistic> collectAllQueryPlanStatistics(boolean reset);
|
||||
|
||||
}
|
||||
@@ -8,17 +8,7 @@ import java.util.List;
|
||||
public interface MetaInfoManager {
|
||||
|
||||
/**
|
||||
* Return the MetaBeanInfo for a bean type.
|
||||
*/
|
||||
MetaBeanInfo getMetaBeanInfo(Class<?> beanClass);
|
||||
|
||||
/**
|
||||
* Return all the MetaBeanInfo.
|
||||
*/
|
||||
List<MetaBeanInfo> getMetaBeanInfoList();
|
||||
|
||||
/**
|
||||
* Collect and return the query plan statistics for all the beans.
|
||||
* Collect and return the non-empty query plan statistics for all the beans.
|
||||
* <p>
|
||||
* Note that this excludes the query plan statistics where there has been no
|
||||
* executions (since the last collection with reset).
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -14,6 +16,11 @@ public interface MetaQueryPlanStatistic {
|
||||
*/
|
||||
Class<?> getBeanType();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Return true if this query plan was tuned by AutoTune.
|
||||
*/
|
||||
|
||||
@@ -180,9 +180,14 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Check for a single "equal to" expression for the Id.
|
||||
* Return true if this is a "find by id" query. This includes a check for a single "equal to" expression for the Id.
|
||||
*/
|
||||
void checkIdEqualTo();
|
||||
boolean isFindById();
|
||||
|
||||
/**
|
||||
* Return true if this is a "find all" query. Used to set a "find all" profile location if necessary.
|
||||
*/
|
||||
boolean isFindAll();
|
||||
|
||||
/**
|
||||
* Return true if AutoTune should be attempted on this query.
|
||||
|
||||
@@ -21,10 +21,14 @@ public class CObjectGraphNodeStatistics {
|
||||
|
||||
private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
|
||||
|
||||
public CObjectGraphNodeStatistics(ObjectGraphNode node) {
|
||||
CObjectGraphNodeStatistics(ObjectGraphNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return count.sum() == 0;
|
||||
}
|
||||
|
||||
public void add(long beanCount, long exeMicros) {
|
||||
count.increment();
|
||||
totalTime.add(exeMicros);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.meta.MetaBeanInfo;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.meta.MetaObjectGraphNodeStats;
|
||||
import io.ebean.meta.MetaQueryPlanStatistic;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.query.CQueryPlanStatsCollector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -15,41 +16,27 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
|
||||
private final DefaultServer server;
|
||||
|
||||
public DefaultMetaInfoManager(DefaultServer server) {
|
||||
DefaultMetaInfoManager(DefaultServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaBeanInfo getMetaBeanInfo(Class<?> beanClass) {
|
||||
return server.getBeanDescriptor(beanClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaBeanInfo> getMetaBeanInfoList() {
|
||||
|
||||
return new ArrayList<>(server.getBeanDescriptors());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlanStatistic> collectQueryPlanStatistics(boolean reset) {
|
||||
|
||||
List<MetaQueryPlanStatistic> list = new ArrayList<>();
|
||||
for (MetaBeanInfo metaBeanInfo : getMetaBeanInfoList()) {
|
||||
list.addAll(metaBeanInfo.collectQueryPlanStatistics(reset));
|
||||
CQueryPlanStatsCollector collector = new CQueryPlanStatsCollector(reset);
|
||||
for (BeanDescriptor<?> desc : server.getBeanDescriptors()) {
|
||||
desc.collectQueryPlanStatistics(collector);
|
||||
}
|
||||
return list;
|
||||
return collector.getList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaObjectGraphNodeStats> collectNodeStatistics(boolean reset) {
|
||||
|
||||
List<MetaObjectGraphNodeStats> list = new ArrayList<>();
|
||||
|
||||
for (CObjectGraphNodeStatistics nodeStatistics : server.objectGraphStats.values()) {
|
||||
MetaObjectGraphNodeStats nodeStats = nodeStatistics.get(reset);
|
||||
if (nodeStats.getCount() > 0) {
|
||||
// Only collection non-empty statistics
|
||||
list.add(nodeStats);
|
||||
if (!nodeStatistics.isEmpty()) {
|
||||
list.add(nodeStatistics.get(reset));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
|
||||
@@ -1133,6 +1133,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
query.selectAllForLazyLoadProperty();
|
||||
|
||||
ProfileLocation profileLocation = query.getProfileLocation();
|
||||
if (profileLocation != null) {
|
||||
profileLocation.obtain();
|
||||
}
|
||||
// if determine cost and no origin for AutoTune
|
||||
if (query.getParentNode() == null) {
|
||||
query.setOrigin(createCallStack());
|
||||
@@ -1213,6 +1217,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(spiQuery, t);
|
||||
request.profileLocationById();
|
||||
if (request.isUseDocStore()) {
|
||||
return docStore().find(request);
|
||||
}
|
||||
@@ -1234,9 +1239,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
public <T> T findOne(Query<T> query, Transaction transaction) {
|
||||
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
|
||||
spiQuery.checkIdEqualTo();
|
||||
Object id = spiQuery.getId();
|
||||
if (id != null) {
|
||||
if (spiQuery.isFindById()) {
|
||||
// actually a find by Id query
|
||||
return findId(query, transaction);
|
||||
}
|
||||
@@ -1537,6 +1540,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
private <T> List<T> findList(Query<T> query, Transaction t, boolean findOne) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
request.profileLocationAll();
|
||||
request.resetBeanCacheAutoMode(findOne);
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
|
||||
@@ -96,6 +96,20 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return queryEngine.translate(this, bindLog, sql, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profileLocationById() {
|
||||
if (query.getProfileLocation() == null) {
|
||||
query.setProfileLocation(beanDescriptor.profileLocationById());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profileLocationAll() {
|
||||
if (query.getProfileLocation() == null && query.isFindAll()) {
|
||||
query.setProfileLocation(beanDescriptor.profileLocationAll());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiValueIdSupported() {
|
||||
return beanDescriptor.isMultiValueIdSupported();
|
||||
|
||||
@@ -155,4 +155,14 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
|
||||
* Return true if this query is expected to use the doc store.
|
||||
*/
|
||||
boolean isUseDocStore();
|
||||
|
||||
/**
|
||||
* Set profile location for "find by id" if not set.
|
||||
*/
|
||||
void profileLocationById();
|
||||
|
||||
/**
|
||||
* Set profile location for "find all" if not set.
|
||||
*/
|
||||
void profileLocationAll();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
@@ -27,8 +28,6 @@ import io.ebean.event.changelog.ChangeType;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
import io.ebean.meta.MetaBeanInfo;
|
||||
import io.ebean.meta.MetaQueryPlanStatistic;
|
||||
import io.ebean.plugin.BeanDocType;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.ExpressionPath;
|
||||
@@ -63,7 +62,7 @@ import io.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.persist.DmlUtil;
|
||||
import io.ebeaninternal.server.query.CQueryPlan;
|
||||
import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
|
||||
import io.ebeaninternal.server.query.CQueryPlanStatsCollector;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.rawsql.SpiRawSql;
|
||||
import io.ebeaninternal.server.text.json.ReadJson;
|
||||
@@ -100,7 +99,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
*/
|
||||
public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
public class BeanDescriptor<T> implements BeanType<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanDescriptor.class);
|
||||
|
||||
@@ -119,6 +118,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
private final Map<String, String> namedQuery;
|
||||
|
||||
private final short profileBeanId;
|
||||
private final ProfileLocation locationById;
|
||||
private final ProfileLocation locationAll;
|
||||
|
||||
private final boolean multiValueSupported;
|
||||
|
||||
@@ -415,6 +416,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
this.name = InternString.intern(deploy.getName());
|
||||
this.baseTableAlias = "t0";
|
||||
this.fullName = InternString.intern(deploy.getFullName());
|
||||
this.locationById = ProfileLocation.create(fullName+".byId");
|
||||
this.locationAll = ProfileLocation.create(fullName+".all");
|
||||
this.profileBeanId = deploy.getProfileId();
|
||||
this.beanType = deploy.getBeanType();
|
||||
this.rootBeanType = PersistenceContextUtil.root(beanType);
|
||||
@@ -537,6 +540,20 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a location for "find by id".
|
||||
*/
|
||||
public ProfileLocation profileLocationById() {
|
||||
return locationById;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a location for "find all".
|
||||
*/
|
||||
public ProfileLocation profileLocationAll() {
|
||||
return locationAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id used in profiling to identify the bean type.
|
||||
*/
|
||||
@@ -1528,25 +1545,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return new DeployUpdateParser(this).parse(ormUpdateStatement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlanStatistic> collectQueryPlanStatistics(boolean reset) {
|
||||
return collectQueryPlanStatisticsInternal(reset, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlanStatistic> collectAllQueryPlanStatistics(boolean reset) {
|
||||
return collectQueryPlanStatisticsInternal(reset, false);
|
||||
}
|
||||
|
||||
public List<MetaQueryPlanStatistic> collectQueryPlanStatisticsInternal(boolean reset, boolean collectAll) {
|
||||
List<MetaQueryPlanStatistic> list = new ArrayList<>(queryPlanCache.size());
|
||||
public void collectQueryPlanStatistics(CQueryPlanStatsCollector collector) {
|
||||
for (CQueryPlan queryPlan : queryPlanCache.values()) {
|
||||
Snapshot snapshot = queryPlan.getSnapshot(reset);
|
||||
if (collectAll || snapshot.getExecutionCount() > 0) {
|
||||
list.add(snapshot);
|
||||
if (!queryPlan.isEmptyStats()) {
|
||||
collector.add(queryPlan.getSnapshot(collector.isReset()));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,17 +8,35 @@ import io.ebean.ProfileLocation;
|
||||
class BasicProfileLocation implements ProfileLocation {
|
||||
|
||||
private final String location;
|
||||
private final String shortDescription;
|
||||
|
||||
BasicProfileLocation(String location) {
|
||||
this.location = location;
|
||||
this.shortDescription = shortDesc(location);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "location: " + location;
|
||||
return shortDescription;
|
||||
}
|
||||
|
||||
public String obtain() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return shortDescription;
|
||||
}
|
||||
|
||||
private String shortDesc(String location) {
|
||||
int lastPer = location.lastIndexOf('.');
|
||||
if (lastPer > -1) {
|
||||
lastPer = location.lastIndexOf('.', lastPer-1);
|
||||
if (lastPer > -1) {
|
||||
return location.substring(lastPer+1);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ class DProfileLocation implements ProfileLocation {
|
||||
|
||||
private String location;
|
||||
|
||||
private String shortDescription;
|
||||
|
||||
private final int lineNumber;
|
||||
|
||||
DProfileLocation() {
|
||||
@@ -31,10 +33,16 @@ class DProfileLocation implements ProfileLocation {
|
||||
// atomic assignment so happy with this
|
||||
if (location == null) {
|
||||
location = create();
|
||||
shortDescription = shortDesc(location);
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return shortDescription;
|
||||
}
|
||||
|
||||
private String create() {
|
||||
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
for (int i = 3; i < trace.length; i++) {
|
||||
@@ -52,4 +60,20 @@ class DProfileLocation implements ProfileLocation {
|
||||
return traceLine.substring(0, traceLine.length() - 1) + ":" + lineNumber + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private String shortDesc(String location) {
|
||||
int pos = location.lastIndexOf('(');
|
||||
if (pos == -1) {
|
||||
pos = location.length();
|
||||
}
|
||||
|
||||
pos = location.lastIndexOf('.', pos);
|
||||
if (pos > -1) {
|
||||
pos = location.lastIndexOf('.', pos - 1);
|
||||
if (pos > -1) {
|
||||
return location.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class CQueryBuilder {
|
||||
if (queryPlan != null) {
|
||||
// skip building the SqlTree and Sql string
|
||||
predicates.prepare(false);
|
||||
return new CQueryUpdate(type, request, predicates, queryPlan.getSql());
|
||||
return new CQueryUpdate(type, request, predicates, queryPlan);
|
||||
}
|
||||
|
||||
predicates.prepare(true);
|
||||
@@ -125,7 +125,7 @@ class CQueryBuilder {
|
||||
// cache the query plan
|
||||
queryPlan = new CQueryPlan(request, sql, sqlTree, false, false, predicates.getLogWhereSql());
|
||||
request.putQueryPlan(queryPlan);
|
||||
return new CQueryUpdate(type, request, predicates, sql);
|
||||
return new CQueryUpdate(type, request, predicates, queryPlan);
|
||||
}
|
||||
|
||||
private <T> String buildDeleteSql(OrmQueryRequest<T> request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) {
|
||||
@@ -251,8 +251,7 @@ class CQueryBuilder {
|
||||
if (queryPlan != null) {
|
||||
// skip building the SqlTree and Sql string
|
||||
predicates.prepare(false);
|
||||
String sql = queryPlan.getSql();
|
||||
return new CQueryRowCount(queryPlan, request, predicates, sql);
|
||||
return new CQueryRowCount(queryPlan, request, predicates);
|
||||
}
|
||||
|
||||
predicates.prepare(true);
|
||||
@@ -283,7 +282,7 @@ class CQueryBuilder {
|
||||
queryPlan = new CQueryPlan(request, sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
|
||||
request.putQueryPlan(queryPlan);
|
||||
|
||||
return new CQueryRowCount(queryPlan, request, predicates, sql);
|
||||
return new CQueryRowCount(queryPlan, request, predicates);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,7 +55,6 @@ public class CQueryEngine {
|
||||
this.defaultFetchSizeFindEach = serverConfig.getJdbcFetchSizeFindEach();
|
||||
this.defaultFetchSizeFindList = serverConfig.getJdbcFetchSizeFindList();
|
||||
this.forwardOnlyHintOnFindIterate = dbPlatform.isForwardOnlyHintOnFindIterate();
|
||||
|
||||
this.historySupport = new CQueryHistorySupport(dbPlatform.getHistorySupport(), asOfTableMapping, serverConfig.getAsOfSysPeriod());
|
||||
this.queryBuilder = new CQueryBuilder(dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap));
|
||||
}
|
||||
@@ -331,8 +330,6 @@ public class CQueryEngine {
|
||||
* deemed to be a be a paging query - check that the order by contains the id
|
||||
* property to ensure unique row ordering for predicable paging but only in
|
||||
* case, this is not a distinct query
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
private <T> void prepareForPaging(OrmQueryRequest<T> request) {
|
||||
SpiQuery<T> query = request.getQuery();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
@@ -18,10 +19,12 @@ import java.util.List;
|
||||
/**
|
||||
* Base compiled query request for single attribute queries.
|
||||
*/
|
||||
class CQueryFetchSingleAttribute {
|
||||
class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchSingleAttribute.class);
|
||||
|
||||
private final CQueryPlan queryPlan;
|
||||
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
@@ -56,17 +59,19 @@ class CQueryFetchSingleAttribute {
|
||||
|
||||
private final ScalarType<?> scalarType;
|
||||
|
||||
private long profileOffset;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan plan) {
|
||||
CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan queryPlan) {
|
||||
this.request = request;
|
||||
this.queryPlan = queryPlan;
|
||||
this.query = request.getQuery();
|
||||
this.sql = plan.getSql();
|
||||
this.sql = queryPlan.getSql();
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
this.scalarType = plan.getSingleAttributeScalarType();
|
||||
|
||||
this.scalarType = queryPlan.getSingleAttributeScalarType();
|
||||
query.setGeneratedSql(sql);
|
||||
}
|
||||
|
||||
@@ -102,6 +107,9 @@ class CQueryFetchSingleAttribute {
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
queryPlan.executionTime(rowCount, executionTimeMicros, null);
|
||||
getTransaction().profileEvent(this);
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
@@ -109,6 +117,10 @@ class CQueryFetchSingleAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
private SpiTransaction getTransaction() {
|
||||
return request.getTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
@@ -125,7 +137,8 @@ class CQueryFetchSingleAttribute {
|
||||
|
||||
private void prepareExecute() throws SQLException {
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
SpiTransaction t = getTransaction();
|
||||
profileOffset = t.profileOffset();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
@@ -166,4 +179,10 @@ class CQueryFetchSingleAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profile() {
|
||||
getTransaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.getProfileId(), rowCount, query.getProfileId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import io.ebeaninternal.api.CQueryPlanKey;
|
||||
@@ -48,6 +49,8 @@ public class CQueryPlan {
|
||||
|
||||
private final boolean autoTuned;
|
||||
|
||||
private final ProfileLocation profileLocation;
|
||||
|
||||
private final CQueryPlanKey planKey;
|
||||
|
||||
private final boolean rawSql;
|
||||
@@ -87,6 +90,7 @@ public class CQueryPlan {
|
||||
this.dataTimeZone = server.getDataTimeZone();
|
||||
this.beanType = request.getBeanDescriptor().getBeanType();
|
||||
this.planKey = request.getQueryPlanKey();
|
||||
this.profileLocation = request.getQuery().getProfileLocation();
|
||||
this.autoTuned = request.getQuery().isAutoTuned();
|
||||
this.asOfTableCount = request.getQuery().getAsOfTableCount();
|
||||
this.sql = sqlRes.getSql();
|
||||
@@ -107,6 +111,7 @@ public class CQueryPlan {
|
||||
this.server = request.getServer();
|
||||
this.dataTimeZone = server.getDataTimeZone();
|
||||
this.beanType = request.getBeanDescriptor().getBeanType();
|
||||
this.profileLocation = request.getQuery().getProfileLocation();
|
||||
this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
this.autoTuned = false;
|
||||
this.asOfTableCount = 0;
|
||||
@@ -134,6 +139,10 @@ public class CQueryPlan {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
|
||||
public DataReader createDataReader(ResultSet rset) {
|
||||
return new RsetDataReader(dataTimeZone, rset);
|
||||
}
|
||||
@@ -252,4 +261,11 @@ public class CQueryPlan {
|
||||
ScalarType<?> getSingleAttributeScalarType() {
|
||||
return sqlTree.getRootNode().getSingleAttributeScalarType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no statistics collected since the last reset.
|
||||
*/
|
||||
public boolean isEmptyStats() {
|
||||
return stats.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.meta.MetaQueryPlanOriginCount;
|
||||
import io.ebean.meta.MetaQueryPlanStatistic;
|
||||
@@ -43,6 +44,13 @@ public final class CQueryPlanStats {
|
||||
this.origins = !collectQueryOrigins ? null : new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no statistics collected since the last reset.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return count.sum() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a query execution to the statistics.
|
||||
*/
|
||||
@@ -188,8 +196,9 @@ public final class CQueryPlanStats {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return queryPlan + " count:" + count + " time:" + totalTime + " maxTime:" + maxTime + " beans:" + totalBeans
|
||||
+ " start:" + startTime + " lastQuery:" + lastQueryTime + " origins:" + origins;
|
||||
ProfileLocation profileLocation = queryPlan.getProfileLocation();
|
||||
String loc = (profileLocation == null) ? "" : profileLocation.shortDescription();
|
||||
return "location:" + loc + " count:" + count + " time:" + totalTime + " maxTime:" + maxTime + " beans:" + totalBeans + " sql:" + getSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,6 +206,11 @@ public final class CQueryPlanStats {
|
||||
return queryPlan.getBeanType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return queryPlan.getProfileLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExecutionCount() {
|
||||
return count;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlanStatistic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper to collect query plan execution statistics.
|
||||
*/
|
||||
public class CQueryPlanStatsCollector {
|
||||
|
||||
private final boolean reset;
|
||||
|
||||
List<MetaQueryPlanStatistic> list = new ArrayList<>();
|
||||
|
||||
public CQueryPlanStatsCollector(boolean reset) {
|
||||
this.reset = reset;
|
||||
}
|
||||
|
||||
public boolean isReset() {
|
||||
return reset;
|
||||
}
|
||||
|
||||
public void add(MetaQueryPlanStatistic planStatistic) {
|
||||
list.add(planStatistic);
|
||||
}
|
||||
|
||||
public List<MetaQueryPlanStatistic> getList() {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
@@ -14,7 +15,7 @@ import java.sql.SQLException;
|
||||
/**
|
||||
* Executes the select row count query.
|
||||
*/
|
||||
class CQueryRowCount {
|
||||
class CQueryRowCount implements SpiProfileTransactionEvent {
|
||||
|
||||
private final CQueryPlan queryPlan;
|
||||
|
||||
@@ -53,17 +54,19 @@ class CQueryRowCount {
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private long profileOffset;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
CQueryRowCount(CQueryPlan queryPlan, OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
CQueryRowCount(CQueryPlan queryPlan, OrmQueryRequest<?> request, CQueryPredicates predicates) {
|
||||
this.queryPlan = queryPlan;
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
query.setGeneratedSql(sql);
|
||||
this.sql = queryPlan.getSql();
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
query.setGeneratedSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +105,8 @@ class CQueryRowCount {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
SpiTransaction t = request.getTransaction();
|
||||
SpiTransaction t = getTransaction();
|
||||
profileOffset = t.profileOffset();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
@@ -121,6 +125,7 @@ class CQueryRowCount {
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
queryPlan.executionTime(rowCount, executionTimeMicros, query.getParentNode());
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
getTransaction().profileEvent(this);
|
||||
return rowCount;
|
||||
|
||||
} finally {
|
||||
@@ -128,6 +133,10 @@ class CQueryRowCount {
|
||||
}
|
||||
}
|
||||
|
||||
private SpiTransaction getTransaction() {
|
||||
return request.getTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
*/
|
||||
@@ -138,4 +147,10 @@ class CQueryRowCount {
|
||||
pstmt = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profile() {
|
||||
getTransaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.getProfileId(), rowCount, query.getProfileId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
@@ -12,7 +13,9 @@ import java.sql.SQLException;
|
||||
/**
|
||||
* Executes the delete query.
|
||||
*/
|
||||
class CQueryUpdate {
|
||||
class CQueryUpdate implements SpiProfileTransactionEvent {
|
||||
|
||||
private final CQueryPlan queryPlan;
|
||||
|
||||
private final OrmQueryRequest<?> request;
|
||||
|
||||
@@ -43,17 +46,20 @@ class CQueryUpdate {
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private long profileOffset;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
CQueryUpdate(String type, OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
CQueryUpdate(String type, OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan queryPlan) {
|
||||
this.type = type;
|
||||
this.request = request;
|
||||
this.queryPlan = queryPlan;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
query.setGeneratedSql(sql);
|
||||
this.sql = queryPlan.getSql();
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
query.setGeneratedSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +96,8 @@ class CQueryUpdate {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
SpiTransaction t = request.getTransaction();
|
||||
SpiTransaction t = getTransaction();
|
||||
profileOffset = t.profileOffset();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
@@ -103,6 +110,8 @@ class CQueryUpdate {
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
queryPlan.executionTime(rowCount, executionTimeMicros, null);
|
||||
getTransaction().profileEvent(this);
|
||||
return rowCount;
|
||||
|
||||
} finally {
|
||||
@@ -110,6 +119,10 @@ class CQueryUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
private SpiTransaction getTransaction() {
|
||||
return request.getTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
*/
|
||||
@@ -118,4 +131,10 @@ class CQueryUpdate {
|
||||
pstmt = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profile() {
|
||||
getTransaction()
|
||||
.profileStream()
|
||||
.addQueryEvent(query.profileEventId(), profileOffset, desc.getProfileId(), rowCount, query.getProfileId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,14 +277,20 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
|
||||
public boolean isFindAll() {
|
||||
return whereExpressions == null && nativeSql == null && rawSql == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkIdEqualTo() {
|
||||
public boolean isFindById() {
|
||||
if (id == null && whereExpressions != null) {
|
||||
id = whereExpressions.idEqualTo(beanDescriptor.getIdName());
|
||||
if (id != null) {
|
||||
whereExpressions = null;
|
||||
}
|
||||
}
|
||||
return id != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -715,6 +721,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
DefaultOrmQuery<T> copy = new DefaultOrmQuery<>(beanDescriptor, server, expressionFactory);
|
||||
copy.m2mIncludeJoin = m2mIncludeJoin;
|
||||
copy.profilingListener = profilingListener;
|
||||
copy.profileLocation = profileLocation;
|
||||
|
||||
copy.rootTableAlias = rootTableAlias;
|
||||
copy.distinct = distinct;
|
||||
|
||||
Reference in New Issue
Block a user