Skip to content

Commit dad9b35

Browse files
ravidarbhaRaviprakash DarbhaB-Step62
authored
feat(tracking): Add composite index on metrics (run_uuid, key, step) (mlflow#21727)
Signed-off-by: Raviprakash Darbha <rdarbha@amazon.com> Signed-off-by: Yuki Watanabe <31463517+B-Step62@users.noreply.github.com> Co-authored-by: Raviprakash Darbha <rdarbha@amazon.com> Co-authored-by: Yuki Watanabe <31463517+B-Step62@users.noreply.github.com>
1 parent 7f7011f commit dad9b35

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""add composite index on metrics (run_uuid, key, step)
2+
3+
Create Date: 2026-03-10 20:46:00.000000
4+
5+
"""
6+
7+
from alembic import op
8+
9+
# revision identifiers, used by Alembic.
10+
revision = "a5b4c3d2e1f0"
11+
down_revision = "c3d6457b6d8a"
12+
branch_labels = None
13+
depends_on = None
14+
15+
16+
def upgrade():
17+
# Add composite index to speed up metric history queries that filter by
18+
# run_uuid and key, and order by step. See https://github.com/mlflow/mlflow/issues/12813
19+
op.create_index("index_metrics_run_uuid_key_step", "metrics", ["run_uuid", "key", "step"])
20+
21+
22+
def downgrade():
23+
op.drop_index("index_metrics_run_uuid_key_step", table_name="metrics")

mlflow/store/tracking/dbmodels/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ class SqlMetric(Base):
398398
"key", "timestamp", "step", "run_uuid", "value", "is_nan", name="metric_pk"
399399
),
400400
Index(f"index_{__tablename__}_run_uuid", "run_uuid"),
401+
Index(f"index_{__tablename__}_run_uuid_key_step", "run_uuid", "key", "step"),
401402
)
402403

403404
key = Column(String(250))

tests/store/tracking/test_sqlalchemy_store_schema.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,38 @@ def test_create_index_on_run_uuid(tmp_path, db_url):
147147
assert run_uuid_index_names.issubset(all_index_names)
148148

149149

150+
def test_create_index_on_metrics_run_uuid_key_step_via_migration(tmp_path, db_url):
151+
# Test that the index is created when upgrading from initial schema via migrations
152+
engine = sqlalchemy.create_engine(db_url)
153+
InitialBase.metadata.create_all(engine)
154+
invoke_cli_runner(mlflow.db.commands, ["upgrade", db_url])
155+
with sqlite3.connect(db_url[len("sqlite:///") :]) as conn:
156+
cursor = conn.cursor()
157+
cursor.execute("SELECT name FROM sqlite_master WHERE type = 'index'")
158+
all_index_names = [r[0] for r in cursor.fetchall()]
159+
assert "index_metrics_run_uuid_key_step" in all_index_names
160+
161+
cursor.execute("PRAGMA index_info('index_metrics_run_uuid_key_step')")
162+
columns = [row[2] for row in cursor.fetchall()]
163+
assert columns == ["run_uuid", "key", "step"]
164+
165+
166+
def test_create_index_on_metrics_run_uuid_key_step(tmp_path, db_url):
167+
# Test for
168+
# mlflow/store/db_migrations/versions/a5b4c3d2e1f0_add_metrics_run_key_step_index.py
169+
SqlAlchemyStore(db_url, tmp_path.joinpath("ARTIFACTS").as_uri())
170+
with sqlite3.connect(db_url[len("sqlite:///") :]) as conn:
171+
cursor = conn.cursor()
172+
cursor.execute("SELECT name FROM sqlite_master WHERE type = 'index'")
173+
all_index_names = [r[0] for r in cursor.fetchall()]
174+
assert "index_metrics_run_uuid_key_step" in all_index_names
175+
176+
# Verify the index columns and order
177+
cursor.execute("PRAGMA index_info('index_metrics_run_uuid_key_step')")
178+
columns = [row[2] for row in cursor.fetchall()]
179+
assert columns == ["run_uuid", "key", "step"]
180+
181+
150182
def test_index_for_dataset_tables(tmp_path, db_url):
151183
# Test for
152184
# mlflow/store/db_migrations/versions/7f2a7d5fae7d_add_datasets_inputs_input_tags_tables.py

0 commit comments

Comments
 (0)