Skip to content

feat: add index on actions(time) to improve time-range query performance#369

Open
netcrafts wants to merge 1 commit intoQuiltServerTools:masterfrom
netcrafts:feat/index-actions-time
Open

feat: add index on actions(time) to improve time-range query performance#369
netcrafts wants to merge 1 commit intoQuiltServerTools:masterfrom
netcrafts:feat/index-actions-time

Conversation

@netcrafts
Copy link
Copy Markdown

Problem

The actions table has indexes on action_id, object_id, old_object_id,
source, player_id, and a composite (x, y, z, world_id) — but no index on
the time column. This means every time-range query (/ledger lookup before:... after:...) and every auto-purge (deleteWhere { timestamp lessEq ... }) performs
a full table scan on the largest column in the database.

Changes

1. New databases — Tables.kt

The timestamp column declaration in Actions now includes .index("actions_time"):

val timestamp = timestamp("time").index("actions_time")

This follows the same pattern used by every other indexed column in the table.
Exposed's SchemaUtils.create() will include the index when creating the table
for the first time.

2. Existing databases — DatabaseManager.kt

ensureTables() now runs an idempotent CREATE INDEX IF NOT EXISTS after
SchemaUtils.create(), which creates the index on databases that already
existed before this change:

try {
    exec("CREATE INDEX IF NOT EXISTS actions_time ON actions(time)")
} catch (e: java.sql.SQLException) {
    logWarn("Could not create actions_time index (MySQL 8.0.12+ required if using MySQL): ${e.message}")
}

The try/catch on SQLException handles the edge case where CREATE INDEX IF NOT EXISTS is not supported — this syntax was added in MySQL 8.0.12 (it is
supported in all versions of SQLite, MariaDB, and PostgreSQL). On an incompatible
MySQL version the server logs a warning and continues normally rather than
crashing on startup. MySQL 5.7 is EOL so this is an unlikely scenario in practice.

Testing

Tested on a live MariaDB 10.11 server:

  • Verified before the update that no index on time existed (SHOW INDEX FROM actions WHERE Column_name = 'time' returned empty)
  • Installed the updated mod
  • Verified after server startup that actions_time BTREE index was present and correct

Note: Testing was done on a small database. On very large existing databases, the CREATE INDEX IF NOT EXISTS in ensureTables() may take significant time to complete on first startup after the update, as the index is built over all existing rows. This blocks server startup until complete. We have not tested this scenario.

@netcrafts netcrafts requested a review from a team as a code owner April 7, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant