Skip to content

Commit a34e56e

Browse files
committed
Lookup performance improvements
1 parent b745a60 commit a34e56e

29 files changed

Lines changed: 2114 additions & 182 deletions

docs/config.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The default settings are suitable for most servers:
2424
```yaml
2525
database-type: duckdb
2626
duckdb-memory-limit: 512MB
27-
duckdb-threads: 2
27+
duckdb-threads: 3
2828
duckdb-max-temp-directory-size: 10GB
2929
```
3030

src/main/java/net/coreprotect/api/BlockAPI.java

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import net.coreprotect.config.Config;
1616
import net.coreprotect.config.ConfigHandler;
1717
import net.coreprotect.database.Database;
18+
import net.coreprotect.database.DuckDBLookupQuery;
1819
import net.coreprotect.database.statement.UserStatement;
1920
import net.coreprotect.utility.BlockUtils;
2021
import net.coreprotect.utility.DatabaseUtils;
@@ -72,7 +73,9 @@ public static List<String[]> performLookup(Block block, int offset) {
7273
}
7374

7475
try (Statement statement = connection.createStatement()) {
75-
String query = "SELECT time," + ConfigHandler.databaseType.getUserColumn() + ",action,type,data,blockdata,rolled_back FROM " + ConfigHandler.prefix + "block " + WorldUtils.getWidIndex("block") + "WHERE wid = " + worldId + " AND x = " + x + " AND z = " + z + " AND y = " + y + " AND time > " + checkTime + " ORDER BY rowid DESC";
76+
String table = DuckDBLookupQuery.spatialTable(connection, "block", worldId, x, x, z, z, "spatial_rows");
77+
String index = ConfigHandler.databaseType.isDuckDB() ? "" : WorldUtils.getWidIndex("block");
78+
String query = "SELECT time," + ConfigHandler.databaseType.getUserColumn() + ",action,type,data,blockdata,rolled_back FROM " + table + " " + index + "WHERE wid = " + worldId + " AND x = " + x + " AND z = " + z + " AND y = " + y + " AND time > " + checkTime + " ORDER BY rowid DESC";
7679

7780
try (ResultSet results = statement.executeQuery(query)) {
7881
while (results.next()) {
@@ -147,7 +150,10 @@ public static List<BlockResult> performLookup(Block block, LookupOptions options
147150
int worldId = WorldUtils.getWorldId(worldName);
148151

149152
StringBuilder query = new StringBuilder("SELECT time," + ConfigHandler.databaseType.getUserColumn() + ",action,type,data,blockdata,rolled_back,wid,x,y,z FROM ");
150-
query.append(ConfigHandler.prefix).append("block ").append(WorldUtils.getWidIndex("block"));
153+
query.append(DuckDBLookupQuery.spatialTable(connection, "block", worldId, x, x, z, z, "spatial_rows")).append(' ');
154+
if (!ConfigHandler.databaseType.isDuckDB()) {
155+
query.append(WorldUtils.getWidIndex("block"));
156+
}
151157
query.append("WHERE wid = ? AND x = ? AND z = ? AND y = ? AND time > ?");
152158
if (userId != null) {
153159
query.append(" AND ").append(ConfigHandler.databaseType.getUserColumn()).append(" = ?");
@@ -223,30 +229,36 @@ public static List<ContainerResult> performContainerLookup(LookupOptions options
223229
return result;
224230
}
225231

226-
StringBuilder containerWhere = new StringBuilder();
227-
filter.appendWhere(containerWhere, "container_rows");
228-
StringBuilder entityWhere = new StringBuilder();
229-
filter.appendEntityContainerWhere(entityWhere, "entity_rows");
230-
231-
StringBuilder query = new StringBuilder("SELECT * FROM (");
232-
query.append("SELECT 0 AS source,container_rows.rowid AS id,container_rows.time,container_rows.").append(ConfigHandler.databaseType.getUserColumn()).append(",container_rows.wid,container_rows.x,container_rows.y,container_rows.z,container_rows.action,container_rows.type,container_rows.data,container_rows.amount,container_rows.metadata,container_rows.rolled_back FROM ")
233-
.append(ConfigHandler.prefix).append("container container_rows ").append(containerWhere);
234-
query.append(" UNION ALL ");
235-
query.append("SELECT 1 AS source,entity_rows.rowid AS id,entity_rows.time,entity_rows.").append(ConfigHandler.databaseType.getUserColumn()).append(",spawn_rows.current_wid AS wid,spawn_rows.x,spawn_rows.y,spawn_rows.z,entity_rows.action,entity_rows.type,entity_rows.data,entity_rows.amount,entity_rows.metadata,entity_rows.rolled_back FROM ")
236-
.append(ConfigHandler.prefix).append("entity_container entity_rows JOIN ").append(ConfigHandler.prefix).append("entity_spawn spawn_rows ON spawn_rows.rowid=entity_rows.entity_spawn_rowid ").append(entityWhere);
237-
query.append(") AS container_lookup ORDER BY time DESC,source DESC,id DESC");
238-
filter.appendLimit(query);
239-
240-
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
241-
int parameterIndex = filter.bind(statement);
242-
filter.bindEntityContainer(statement, parameterIndex);
243-
244-
try (ResultSet results = statement.executeQuery()) {
245-
while (results.next()) {
246-
result.add(parseContainerResult(connection, results));
232+
boolean snapshot = filter.beginDuckDBSnapshot(connection);
233+
try {
234+
StringBuilder containerWhere = new StringBuilder();
235+
filter.appendWhere(containerWhere, "container_rows");
236+
StringBuilder entityWhere = new StringBuilder();
237+
filter.appendEntityContainerWhere(entityWhere, "entity_rows", "spawn_rows");
238+
239+
StringBuilder query = new StringBuilder("SELECT * FROM (");
240+
query.append("SELECT 0 AS source,container_rows.rowid AS id,container_rows.time,container_rows.").append(ConfigHandler.databaseType.getUserColumn()).append(",container_rows.wid,container_rows.x,container_rows.y,container_rows.z,container_rows.action,container_rows.type,container_rows.data,container_rows.amount,container_rows.metadata,container_rows.rolled_back FROM ")
241+
.append(filter.table(connection, "container", "container_rows")).append(' ').append(containerWhere);
242+
query.append(" UNION ALL ");
243+
query.append("SELECT 1 AS source,entity_rows.rowid AS id,entity_rows.time,entity_rows.").append(ConfigHandler.databaseType.getUserColumn()).append(",spawn_rows.current_wid AS wid,spawn_rows.x,spawn_rows.y,spawn_rows.z,entity_rows.action,entity_rows.type,entity_rows.data,entity_rows.amount,entity_rows.metadata,entity_rows.rolled_back FROM ")
244+
.append(filter.entityContainerTable(connection, "entity_rows")).append(" JOIN ").append(ConfigHandler.prefix).append("entity_spawn spawn_rows ON spawn_rows.rowid=entity_rows.entity_spawn_rowid ").append(entityWhere);
245+
query.append(") AS container_lookup ORDER BY time DESC,source DESC,id DESC");
246+
filter.appendLimit(query);
247+
248+
try (PreparedStatement statement = connection.prepareStatement(query.toString())) {
249+
int parameterIndex = filter.bind(statement);
250+
filter.bindEntityContainer(statement, parameterIndex);
251+
252+
try (ResultSet results = statement.executeQuery()) {
253+
while (results.next()) {
254+
result.add(parseContainerResult(connection, results));
255+
}
247256
}
248257
}
249258
}
259+
finally {
260+
filter.endDuckDBSnapshot(connection, snapshot);
261+
}
250262
}
251263
catch (Exception e) {
252264
ErrorReporter.report(e);

src/main/java/net/coreprotect/api/InventoryAPI.java

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,29 +47,43 @@ public static List<InventoryResult> performLookup(LookupOptions options) {
4747
return result;
4848
}
4949

50-
StringBuilder whereBuilder = new StringBuilder();
51-
filter.appendWhere(whereBuilder);
52-
String where = whereBuilder.toString();
53-
StringBuilder entityWhereBuilder = new StringBuilder();
54-
filter.appendEntityContainerWhere(entityWhereBuilder, "entity_rows");
55-
String query = buildQuery(where, entityWhereBuilder.toString(), options.hasLimit());
56-
57-
try (PreparedStatement statement = connection.prepareStatement(query)) {
58-
int parameterIndex = filter.bind(statement);
59-
parameterIndex = filter.bind(statement, parameterIndex);
60-
parameterIndex = filter.bindEntityContainer(statement, parameterIndex);
61-
parameterIndex = filter.bind(statement, parameterIndex);
62-
if (options.hasLimit()) {
63-
statement.setInt(parameterIndex++, options.getLimitCount());
64-
statement.setInt(parameterIndex, options.getLimitOffset());
65-
}
50+
boolean snapshot = filter.beginDuckDBSnapshot(connection);
51+
try {
52+
StringBuilder whereBuilder = new StringBuilder();
53+
filter.appendWhere(whereBuilder);
54+
String where = whereBuilder.toString();
55+
StringBuilder entityWhereBuilder = new StringBuilder();
56+
filter.appendEntityContainerWhere(entityWhereBuilder, "entity_rows", "spawn_rows");
57+
String query = buildQuery(
58+
where,
59+
entityWhereBuilder.toString(),
60+
options.hasLimit(),
61+
filter.table(connection, "block", ""),
62+
filter.table(connection, "container", ""),
63+
filter.entityContainerTable(connection, "entity_rows"),
64+
filter.table(connection, "item", "")
65+
);
66+
67+
try (PreparedStatement statement = connection.prepareStatement(query)) {
68+
int parameterIndex = filter.bind(statement);
69+
parameterIndex = filter.bind(statement, parameterIndex);
70+
parameterIndex = filter.bindEntityContainer(statement, parameterIndex);
71+
parameterIndex = filter.bind(statement, parameterIndex);
72+
if (options.hasLimit()) {
73+
statement.setInt(parameterIndex++, options.getLimitCount());
74+
statement.setInt(parameterIndex, options.getLimitOffset());
75+
}
6676

67-
try (ResultSet results = statement.executeQuery()) {
68-
while (results.next()) {
69-
result.add(parseInventoryResult(connection, results));
77+
try (ResultSet results = statement.executeQuery()) {
78+
while (results.next()) {
79+
result.add(parseInventoryResult(connection, results));
80+
}
7081
}
7182
}
7283
}
84+
finally {
85+
filter.endDuckDBSnapshot(connection, snapshot);
86+
}
7387
}
7488
catch (Exception e) {
7589
ErrorReporter.report(e);
@@ -78,19 +92,19 @@ public static List<InventoryResult> performLookup(LookupOptions options) {
7892
return result;
7993
}
8094

81-
private static String buildQuery(String where, String entityWhere, boolean hasLimit) {
95+
private static String buildQuery(String where, String entityWhere, boolean hasLimit, String blockTable, String containerTable, String entityContainerTable, String itemTable) {
8296
StringBuilder query = new StringBuilder("SELECT * FROM (");
8397
query.append("SELECT 0 AS source,rowid AS id,time,").append(ConfigHandler.databaseType.getUserColumn()).append(",wid,x,y,z,type,data,1 AS amount,meta AS metadata,action,rolled_back FROM ")
84-
.append(ConfigHandler.prefix).append("block ").append(where).append(" AND action = 1");
98+
.append(blockTable).append(' ').append(where).append(" AND action = 1");
8599
query.append(" UNION ALL ");
86100
query.append("SELECT 1 AS source,rowid AS id,time,").append(ConfigHandler.databaseType.getUserColumn()).append(",wid,x,y,z,type,data,amount,metadata,action,rolled_back FROM ")
87-
.append(ConfigHandler.prefix).append("container ").append(where);
101+
.append(containerTable).append(' ').append(where);
88102
query.append(" UNION ALL ");
89103
query.append("SELECT ").append(InventorySources.ENTITY_CONTAINER).append(" AS source,entity_rows.rowid AS id,entity_rows.time,entity_rows.").append(ConfigHandler.databaseType.getUserColumn()).append(",spawn_rows.current_wid AS wid,spawn_rows.x,spawn_rows.y,spawn_rows.z,entity_rows.type,entity_rows.data,entity_rows.amount,entity_rows.metadata,entity_rows.action,entity_rows.rolled_back FROM ")
90-
.append(ConfigHandler.prefix).append("entity_container entity_rows JOIN ").append(ConfigHandler.prefix).append("entity_spawn spawn_rows ON spawn_rows.rowid=entity_rows.entity_spawn_rowid ").append(entityWhere);
104+
.append(entityContainerTable).append(" JOIN ").append(ConfigHandler.prefix).append("entity_spawn spawn_rows ON spawn_rows.rowid=entity_rows.entity_spawn_rowid ").append(entityWhere);
91105
query.append(" UNION ALL ");
92106
query.append("SELECT 2 AS source,rowid AS id,time,").append(ConfigHandler.databaseType.getUserColumn()).append(",wid,x,y,z,type,0 AS data,amount,data AS metadata,action,rolled_back FROM ")
93-
.append(ConfigHandler.prefix).append("item ").append(where);
107+
.append(itemTable).append(' ').append(where);
94108
query.append(") AS inventory_lookup ORDER BY time DESC, source DESC, id DESC");
95109
if (hasLimit) {
96110
query.append(" LIMIT ? OFFSET ?");

src/main/java/net/coreprotect/api/ItemAPI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ public static List<ItemResult> performLookup(LookupOptions options) {
4343
}
4444

4545
StringBuilder query = new StringBuilder("SELECT time," + ConfigHandler.databaseType.getUserColumn() + ",wid,x,y,z,type,data,amount,action,rolled_back FROM ");
46-
query.append(ConfigHandler.prefix).append("item ");
47-
if (filter.hasLocation()) {
46+
query.append(filter.table(connection, "item", "")).append(' ');
47+
if (filter.hasLocation() && !ConfigHandler.databaseType.isDuckDB()) {
4848
query.append(WorldUtils.getWidIndex("item"));
4949
}
5050
filter.appendWhere(query);

0 commit comments

Comments
 (0)