mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
perf(db): index LiteLLM_SpendLogs on (api_key, startTime)
The Logs tab filters LiteLLM_SpendLogs by api_key inside a startTime window. The table only had indexes on startTime, (startTime, request_id), end_user and session_id, so the api_key predicate degraded to a full scan of the window on both the pagination count and the paged select, re-run on every page turn. On a multi-month table that pinned a customer's Aurora writer near 100% CPU for ~50 minutes. Built CONCURRENTLY: this is the largest table on most deployments, and a blocking build would stall spend-log inserts for the whole build.
This commit is contained in:
parent
c6fad3683d
commit
ab3bcb95ef
4 changed files with 53 additions and 0 deletions
|
|
@ -0,0 +1,11 @@
|
|||
-- CreateIndex (CONCURRENTLY)
|
||||
--
|
||||
-- Disclaimer:
|
||||
-- - CREATE INDEX CONCURRENTLY cannot run inside a transaction. This migration must stay a
|
||||
-- single statement so Prisma Migrate on PostgreSQL can apply it outside a transaction.
|
||||
-- - "LiteLLM_SpendLogs" is the largest table on most deployments, so a blocking build would
|
||||
-- stall spend-log inserts for the whole build; if the build is interrupted, Postgres may
|
||||
-- leave an INVALID index that must be dropped and recreated.
|
||||
-- - Do not edit this file after it has been applied to any database: Prisma checksums
|
||||
-- migrations; add a new migration instead.
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS "LiteLLM_SpendLogs_api_key_startTime_idx" ON "LiteLLM_SpendLogs"("api_key", "startTime" DESC);
|
||||
|
|
@ -645,6 +645,7 @@ model LiteLLM_SpendLogs {
|
|||
@@index([startTime, request_id])
|
||||
@@index([end_user])
|
||||
@@index([session_id])
|
||||
@@index([api_key, startTime(sort: Desc)], map: "LiteLLM_SpendLogs_api_key_startTime_idx")
|
||||
}
|
||||
|
||||
// View spend, model, api_key per request
|
||||
|
|
|
|||
|
|
@ -645,6 +645,7 @@ model LiteLLM_SpendLogs {
|
|||
@@index([startTime, request_id])
|
||||
@@index([end_user])
|
||||
@@index([session_id])
|
||||
@@index([api_key, startTime(sort: Desc)], map: "LiteLLM_SpendLogs_api_key_startTime_idx")
|
||||
}
|
||||
|
||||
// View spend, model, api_key per request
|
||||
|
|
|
|||
|
|
@ -68,3 +68,43 @@ def test_schema_migration_in_sync():
|
|||
assert diff.returncode == 0, f"prisma migrate diff errored: {diff.stderr}"
|
||||
finally:
|
||||
shutil.rmtree(temp_base, ignore_errors=True)
|
||||
|
||||
|
||||
SPEND_LOGS_API_KEY_INDEX = "LiteLLM_SpendLogs_api_key_startTime_idx"
|
||||
|
||||
SCHEMA_PATHS = (
|
||||
Path("./schema.prisma"),
|
||||
Path("./litellm-proxy-extras/litellm_proxy_extras/schema.prisma"),
|
||||
)
|
||||
|
||||
|
||||
def _spend_logs_model_block(schema: str) -> str:
|
||||
start = schema.index("model LiteLLM_SpendLogs {")
|
||||
return schema[start : schema.index("\n}", start)]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("schema_path", SCHEMA_PATHS, ids=lambda p: str(p))
|
||||
def test_spend_logs_declares_api_key_index(schema_path: Path):
|
||||
"""The Logs tab filters ``LiteLLM_SpendLogs`` by ``api_key`` inside a ``startTime``
|
||||
window. Without an index led by ``api_key`` that degrades to a full scan of the
|
||||
window on every page turn, which pinned a customer's Aurora writer at ~99% CPU.
|
||||
"""
|
||||
block = _spend_logs_model_block(schema_path.read_text())
|
||||
assert f'@@index([api_key, startTime(sort: Desc)], map: "{SPEND_LOGS_API_KEY_INDEX}")' in block, (
|
||||
f"{schema_path} must keep the api_key-led index on LiteLLM_SpendLogs"
|
||||
)
|
||||
|
||||
|
||||
def test_spend_logs_api_key_index_has_a_migration():
|
||||
"""A schema-only index never reaches deployments that run ``prisma migrate deploy``."""
|
||||
migrations = Path("./litellm-proxy-extras/litellm_proxy_extras/migrations")
|
||||
creating = [
|
||||
sql
|
||||
for sql in (path.read_text() for path in migrations.glob("*/migration.sql"))
|
||||
if SPEND_LOGS_API_KEY_INDEX in sql
|
||||
]
|
||||
assert len(creating) == 1, f"expected exactly one migration creating {SPEND_LOGS_API_KEY_INDEX}, found {len(creating)}"
|
||||
assert 'ON "LiteLLM_SpendLogs"("api_key", "startTime" DESC)' in creating[0]
|
||||
assert "CONCURRENTLY" in creating[0], (
|
||||
"LiteLLM_SpendLogs is the largest table on most deployments; a blocking build stalls spend-log inserts"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue