org.h2.engine.QueryStatisticsData Maven / Gradle / Ivy
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.engine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
/**
* Maintains query statistics.
*/
public class QueryStatisticsData {
private static final Comparator QUERY_ENTRY_COMPARATOR =
new Comparator() {
@Override
public int compare(QueryEntry o1, QueryEntry o2) {
return (int) Math.signum(o1.lastUpdateTime - o2.lastUpdateTime);
}
};
private final HashMap map =
new HashMap();
private int maxQueryEntries;
public QueryStatisticsData(int maxQueryEntries) {
this.maxQueryEntries = maxQueryEntries;
}
public synchronized void setMaxQueryEntries(int maxQueryEntries) {
this.maxQueryEntries = maxQueryEntries;
}
public synchronized List getQueries() {
// return a copy of the map so we don't have to
// worry about external synchronization
ArrayList list = new ArrayList();
list.addAll(map.values());
// only return the newest 100 entries
Collections.sort(list, QUERY_ENTRY_COMPARATOR);
return list.subList(0, Math.min(list.size(), maxQueryEntries));
}
/**
* Update query statistics.
*
* @param sqlStatement the statement being executed
* @param executionTime the time in milliseconds the query/update took to
* execute
* @param rowCount the query or update row count
*/
public synchronized void update(String sqlStatement, long executionTime,
int rowCount) {
QueryEntry entry = map.get(sqlStatement);
if (entry == null) {
entry = new QueryEntry();
entry.sqlStatement = sqlStatement;
map.put(sqlStatement, entry);
}
entry.update(executionTime, rowCount);
// Age-out the oldest entries if the map gets too big.
// Test against 1.5 x max-size so we don't do this too often
if (map.size() > maxQueryEntries * 1.5f) {
// Sort the entries by age
ArrayList list = new ArrayList();
list.addAll(map.values());
Collections.sort(list, QUERY_ENTRY_COMPARATOR);
// Create a set of the oldest 1/3 of the entries
HashSet oldestSet =
new HashSet(list.subList(0, list.size() / 3));
// Loop over the map using the set and remove
// the oldest 1/3 of the entries.
for (Iterator> it =
map.entrySet().iterator(); it.hasNext();) {
Entry mapEntry = it.next();
if (oldestSet.contains(mapEntry.getValue())) {
it.remove();
}
}
}
}
/**
* The collected statistics for one query.
*/
public static final class QueryEntry {
/**
* The SQL statement.
*/
public String sqlStatement;
/**
* The number of times the statement was executed.
*/
public int count;
/**
* The last time the statistics for this entry were updated,
* in milliseconds since 1970.
*/
public long lastUpdateTime;
/**
* The minimum execution time, in milliseconds.
*/
public long executionTimeMin;
/**
* The maximum execution time, in milliseconds.
*/
public long executionTimeMax;
/**
* The total execution time.
*/
public long executionTimeCumulative;
/**
* The minimum number of rows.
*/
public int rowCountMin;
/**
* The maximum number of rows.
*/
public int rowCountMax;
/**
* The total number of rows.
*/
public long rowCountCumulative;
/**
* The mean execution time.
*/
public double executionTimeMean;
/**
* The mean number of rows.
*/
public double rowCountMean;
// Using Welford's method, see also
// http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
// http://www.johndcook.com/standard_deviation.html
private double executionTimeM2;
private double rowCountM2;
/**
* Update the statistics entry.
*
* @param time the execution time
* @param rows the number of rows
*/
void update(long time, int rows) {
count++;
executionTimeMin = Math.min(time, executionTimeMin);
executionTimeMax = Math.max(time, executionTimeMax);
rowCountMin = Math.min(rows, rowCountMin);
rowCountMax = Math.max(rows, rowCountMax);
double delta = rows - rowCountMean;
rowCountMean += delta / count;
rowCountM2 += delta * (rows - rowCountMean);
delta = time - executionTimeMean;
executionTimeMean += delta / count;
executionTimeM2 += delta * (time - executionTimeMean);
executionTimeCumulative += time;
rowCountCumulative += rows;
lastUpdateTime = System.currentTimeMillis();
}
public double getExecutionTimeStandardDeviation() {
// population standard deviation
return Math.sqrt(executionTimeM2 / count);
}
public double getRowCountStandardDeviation() {
// population standard deviation
return Math.sqrt(rowCountM2 / count);
}
}
}