Benchmark comparing composite indexes (from rotki PR #11464) against single-column indexes for the event_metrics table.
CREATE INDEX idx_em_event ON event_metrics(event_identifier);
CREATE INDEX idx_em_metric_key ON event_metrics(metric_key);
CREATE INDEX idx_em_asset ON event_metrics(asset);-- Same as above, plus:
CREATE INDEX idx_em_metric_key_bucket ON event_metrics(metric_key, location_label, protocol, asset);
CREATE INDEX idx_em_metric_key_event ON event_metrics(metric_key, event_identifier);From rotkehlchen/balances/historical.py get_balances():
SELECT asset, SUM(metric_value) FROM (
SELECT em.asset, em.metric_value, MAX(he.timestamp + he.sequence_index)
FROM event_metrics em JOIN history_events he ON em.event_identifier = he.identifier
WHERE he.ignored = 0 AND em.metric_key = 'balance' AND he.timestamp <= ?
GROUP BY he.location, em.location_label, em.protocol, em.asset
) GROUP BY asset HAVING SUM(metric_value) > 0| Command | Mean [ms] | Min [ms] | Max [ms] |
|---|---|---|---|
query single |
52.2 ± 0.4 | 51.5 | 53.9 |
query composite |
56.1 ± 0.6 | 55.2 | 58.8 |
Summary: Single-column indexes 1.07x faster
| Command | Mean [ms] | Min [ms] | Max [ms] |
|---|---|---|---|
query single |
190.9 ± 2.1 | 186.8 | 194.3 |
query composite |
212.0 ± 2.7 | 207.5 | 218.3 |
Summary: Single-column indexes 1.11x faster
Both configurations produce identical query plans:
QUERY PLAN
|--CO-ROUTINE (subquery-1)
| |--SEARCH em USING INDEX idx_em_metric_key (metric_key=?)
| |--SEARCH he USING INTEGER PRIMARY KEY (rowid=?)
| `--USE TEMP B-TREE FOR GROUP BY
|--SCAN (subquery-1)
`--USE TEMP B-TREE FOR GROUP BY
SQLite only uses idx_em_metric_key in both cases. The composite indexes are not utilized.
The composite indexes from PR #11464 add ~10% overhead without query performance benefit for the get_balances query. The GROUP BY spans both tables (history_events.location + event_metrics.*), so the composite index cannot provide a covering index advantage.
- SQLite (Python sqlite3 module)
- macOS
- Benchmarked with hyperfine