Skip to content

fix(sql): Optimize SpendLogs queries to use timestamp filtering for index usage - #17504

Merged
2 commits merged into
BerriAI:mainfrom
kristianmitk:remove-date-casting-in-sql
Dec 5, 2025
Merged

2 commits merged into
BerriAI:mainfrom
kristianmitk:remove-date-casting-in-sql

Conversation

@kristianmitk

Copy link
Copy Markdown
Contributor

Title

fix: Optimize SpendLogs queries to use timestamp filtering for index usage

Relevant issues

Fixes #17487

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the
    tests/litellm/ directory, Adding
    at least 1 test is a hard requirement
    - see
    details
  • I have added a screenshot of my new test passing locally
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem

Type

🐛 Bug Fix
🚄 Infrastructure

Changes

Problem

SQL queries using BETWEEN $1::date AND $2::date caused PostgreSQL to implicitly cast the startTime timestamp column to DATE, making queries non-sargable and preventing index usage.

This resulted in:

  • Full table sequential scans (~1.44M blocks read per query)
  • Query latency of ~34 seconds for 30-day windows
  • Massive Aurora I/O billing costs
  • Temporary disk spillage during aggregation

Solution

Changed all date filtering queries from:

  WHERE "startTime" BETWEEN $1::date AND $2::date

To index-friendly timestamp filtering:

WHERE "startTime" >= $1::timestamp AND "startTime" < ($2::timestamp + INTERVAL '1 day')

This allows PostgreSQL to use indexes on the startTime column efficiently.

Performance Impact

  • ✅ Observed ~17× faster queries
  • ✅ Enables index usage on startTime column
  • ✅ Drastically reduces Aurora I/O costs on large tables
  • ✅ No behavior changes - results remain identical

Testing

image

@vercel

vercel Bot commented Dec 4, 2025 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
litellm Ready Ready Preview Comment Dec 4, 2025 11:01pm

@CLAassistant

CLAassistant commented Dec 4, 2025 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ghost
ghost merged commit 63fae79 into BerriAI:main Dec 5, 2025
5 of 8 checks passed
ryan-crabbe-berri added a commit that referenced this pull request Apr 11, 2026
… queries

The raw SQL queries in spend_management_endpoints.py, spend_tracking_utils.py,
and analytics_endpoints.py cast date params to ::timestamptz while comparing
against the plain-timestamp "startTime" column. Postgres resolves the type
mismatch by promoting the column using the DB session timezone, which drifts
the filter window and date_trunc buckets whenever session TZ is not UTC —
silently dropping rows at UTC day boundaries and, for narrow windows, losing
rows entirely.

Wraps every such comparison with `AT TIME ZONE 'UTC'` so the param side
resolves to a plain timestamp matching the column type. Both sides end up
as plain timestamp, Postgres does no implicit conversion, and session TZ
plays no role in the query. The fix is constant-foldable so the existing
startTime index (PR #17504) remains usable.

Also marks strptime-produced datetimes as tz-aware UTC at the call sites
for intent clarity and consistency with parse_date.

Fixes #22529 (Logs page missing recent rows under non-UTC session TZ) and
the Global Usage single-day-returns-two-days symptom reported internally.
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…ndex usage (BerriAI#17504)

* fix: optimize SpendLogs queries to use timestamp filtering (BerriAI#17487)

* use timestamptz & enhance test
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
… queries

The raw SQL queries in spend_management_endpoints.py, spend_tracking_utils.py,
and analytics_endpoints.py cast date params to ::timestamptz while comparing
against the plain-timestamp "startTime" column. Postgres resolves the type
mismatch by promoting the column using the DB session timezone, which drifts
the filter window and date_trunc buckets whenever session TZ is not UTC —
silently dropping rows at UTC day boundaries and, for narrow windows, losing
rows entirely.

Wraps every such comparison with `AT TIME ZONE 'UTC'` so the param side
resolves to a plain timestamp matching the column type. Both sides end up
as plain timestamp, Postgres does no implicit conversion, and session TZ
plays no role in the query. The fix is constant-foldable so the existing
startTime index (PR BerriAI#17504) remains usable.

Also marks strptime-produced datetimes as tz-aware UTC at the call sites
for intent clarity and consistency with parse_date.

Fixes BerriAI#22529 (Logs page missing recent rows under non-UTC session TZ) and
the Global Usage single-day-returns-two-days symptom reported internally.
This pull request was closed.

This branch was successfully deployed

1 active deployment
Preview — 741c9ae3 Deployed Dec 4, 2025 by vercel[bot]
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.

[Bug]: SpendLogs aggregation generates non-sargable startTime::date filter → massive Postgres seq scans & Aurora I/O costs

2 participants