提交 1de0bbf7 authored 作者: Thomas Mueller's avatar Thomas Mueller

New system property h2.analyzeAuto.

上级 7aa5829b
......@@ -7,12 +7,13 @@
package org.h2.command.ddl;
import org.h2.command.Prepared;
import org.h2.constant.SysProperties;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.result.ResultInterface;
import org.h2.table.Column;
import org.h2.table.Table;
import org.h2.table.RegularTable;
import org.h2.table.Table;
import org.h2.util.StatementBuilder;
/**
......@@ -23,9 +24,8 @@ public class Analyze extends DefineCommand {
/**
* The sample size.
* The default value is also in the documentation.
*/
private int sampleRows = 10000;
private int sampleRows = SysProperties.ANALYZE_SAMPLE;
public Analyze(Session session) {
super(session);
......@@ -33,13 +33,41 @@ public class Analyze extends DefineCommand {
public int update() {
session.commit(true);
Database db = session.getDatabase();
session.getUser().checkAdmin();
Database db = session.getDatabase();
// TODO do we need to lock the table?
for (Table table : db.getAllTablesAndViews(false)) {
if (!(table instanceof RegularTable)) {
continue;
analyzeTable(session, table, sampleRows, true);
}
return 0;
}
/**
* Analyze this table.
*
* @param session the session
* @param table the table
* @param sample the number of sample rows
* @param manual whether the command was called by the user
*/
public static void analyzeTable(Session session, Table table, int sample, boolean manual) {
if (!(table instanceof RegularTable) || table.isHidden() || session == null) {
return;
}
if (session.getDatabase().isSysTableLocked()) {
return;
}
if (table.isTemporary() && !table.isGlobalTemporary()
&& session.findLocalTempTable(table.getName()) == null) {
return;
}
if (!manual && table.hasSelectTrigger()) {
return;
}
if (table.isLockedExclusively() && !table.isLockedExclusivelyBy(session)) {
return;
}
Database db = session.getDatabase();
StatementBuilder buff = new StatementBuilder("SELECT ");
Column[] columns = table.getColumns();
for (Column col : columns) {
......@@ -47,8 +75,8 @@ public class Analyze extends DefineCommand {
buff.append("SELECTIVITY(").append(col.getSQL()).append(')');
}
buff.append(" FROM ").append(table.getSQL());
if (sampleRows > 0) {
buff.append(" LIMIT 1 SAMPLE_SIZE ").append(sampleRows);
if (sample > 0) {
buff.append(" LIMIT 1 SAMPLE_SIZE ").append(sample);
}
String sql = buff.toString();
Prepared command = session.prepare(sql);
......@@ -60,8 +88,6 @@ public class Analyze extends DefineCommand {
}
db.update(session, table);
}
return 0;
}
public void setTop(int top) {
this.sampleRows = top;
......
......@@ -72,6 +72,23 @@ public class SysProperties {
*/
public static final String USER_HOME = getStringSetting("user.home", "");
/**
* System property <code>h2.analyzeSample</code> (default: 10000).<br />
* The default sample size when analyzing a table.
*/
public static final int ANALYZE_SAMPLE = getIntSetting("h2.analyzeSample", 10000);
/**
* System property <code>h2.analyzeSample</code> (default: 0).<br />
* After changing this many rows, ANALYZE is automatically run for a table.
* Automatically running ANALYZE is disabled if set to 0. If set to 1000,
* then ANALYZE will run against each user table after about 1000 changes to
* that table. The time between running ANALYZE doubles each time since
* starting the database. It is not run on local temporary tables, and
* tables that have a trigger on SELECT.
*/
public static final int ANALYZE_AUTO = getIntSetting("h2.analyzeAuto", 0);
/**
* System property <code>h2.aliasColumnName</code> (default: false).<br />
* When enabled, aliased columns (as in SELECT ID AS I FROM TEST) return the
......
......@@ -562,6 +562,7 @@ public class Database implements DataHandler {
data.persistData = persistent;
data.persistIndexes = persistent;
data.create = create;
data.isHidden = true;
data.session = systemSession;
meta = mainSchema.createTable(data);
IndexColumn[] pkCols = IndexColumn.wrap(new Column[] { columnId });
......
......@@ -374,4 +374,13 @@ public class TriggerObject extends SchemaObjectBase {
}
}
/**
* Check whether this is a select trigger.
*
* @return true if it is
*/
public boolean isSelectTrigger() {
return (typeMask & Trigger.SELECT) != 0;
}
}
......@@ -12,6 +12,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import org.h2.api.DatabaseEventListener;
import org.h2.command.ddl.Analyze;
import org.h2.command.ddl.CreateTableData;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
......@@ -57,6 +58,8 @@ public class RegularTable extends TableBase {
private long lastModificationId;
private boolean containsLargeObject;
private PageDataIndex mainIndex;
private int changesSinceAnalyze;
private int nextAnalyze = SysProperties.ANALYZE_AUTO;
/**
* True if one thread ever was waiting to lock this table. This is to avoid
......@@ -130,6 +133,7 @@ public class RegularTable extends TableBase {
}
throw DbException.convert(e);
}
analyzeIfRequired(session);
}
private void checkRowCount(Session session, Index index, int offset) {
......@@ -344,6 +348,7 @@ public class RegularTable extends TableBase {
}
throw DbException.convert(e);
}
analyzeIfRequired(session);
}
public void truncate(Session session) {
......@@ -353,6 +358,20 @@ public class RegularTable extends TableBase {
index.truncate(session);
}
rowCount = 0;
changesSinceAnalyze = 0;
}
private void analyzeIfRequired(Session session) {
if (nextAnalyze == 0 || nextAnalyze > changesSinceAnalyze++) {
return;
}
changesSinceAnalyze = 0;
int n = 2 * nextAnalyze;
if (n > 0) {
nextAnalyze = n;
}
int rows = SysProperties.ANALYZE_SAMPLE;
Analyze.analyzeTable(session, this, rows, false);
}
public boolean isLockedExclusivelyBy(Session session) {
......
......@@ -741,6 +741,22 @@ public abstract class Table extends SchemaObjectBase {
}
}
/**
* Check whether this table has a select trigger.
*
* @return true if it has
*/
public boolean hasSelectTrigger() {
if (triggers != null) {
for (TriggerObject trigger : triggers) {
if (trigger.isSelectTrigger()) {
return true;
}
}
}
return false;
}
/**
* Check if row based triggers or constraints are defined.
* In this case the fire after and before row methods need to be called.
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论