Skip to content

perf: add query-aligned indexes for Login model (timestamp desc, country upper, ip)#563

Merged
eugenioseveri merged 1 commit intocertego:developfrom
nishantxscooby:perf-login-indexes-final
Feb 9, 2026
Merged

perf: add query-aligned indexes for Login model (timestamp desc, country upper, ip)#563
eugenioseveri merged 1 commit intocertego:developfrom
nishantxscooby:perf-login-indexes-final

Conversation

@nishantxscooby
Copy link
Contributor

🎯 Problem Statement

Fixes #494 (Part 1: Login Model Indexes)

BuffaLogs has performance issues due to missing database indexes on the Login model. Queries using timestamp, country, and ip fields are performing full table scans, causing:

  • Slow query execution (especially with ORDER BY -timestamp)
  • High database CPU usage under normal load
  • Poor scalability as data grows beyond 100k+ records

🔍 Solution

Added 3 query-aligned indexes to the Login model based on comprehensive codebase analysis:

1. Descending Timestamp Index

models.Index(fields=["-timestamp"], name="login_timestamp_desc_idx")
  • Query Pattern: Login.objects.filter(...).order_by("-timestamp") (used in 10+ locations)
  • Files: models.py:76, dashboards/charts.py, views/logins.py:25
  • Impact: Optimizes descending time-based sorting

2. Functional Country Index (Case-Insensitive)

models.Index(Upper("country"), name="login_country_upper_idx")
  • Query Pattern: Login.objects.filter(country__iexact=...) (used in 8+ locations)
  • Files: models.py:89, detection.py:138, dashboards/charts.py
  • Impact: Supports case-insensitive country lookups without full table scans

3. IP Address Index

models.Index(fields=["ip"], name="login_ip_idx")
  • Query Pattern: Login.objects.filter(ip=...) (exact matches)
  • Files: models.py:81, detection queries
  • Impact: Fast IP-based filtering

✅ Verification

Database Indexes Created:

-- Verified with: SELECT * FROM pg_indexes WHERE tablename = 'impossible_travel_login';

login_timestamp_desc_idx | CREATE INDEX login_timestamp_desc_idx ON impossible_travel_login (timestamp DESC)
login_country_upper_idx  | CREATE INDEX login_country_upper_idx ON impossible_travel_login (UPPER(country))
login_ip_idx             | CREATE INDEX login_ip_idx ON impossible_travel_login (ip)

Query Performance (EXPLAIN ANALYZE):

Test 1: Timestamp Descending

EXPLAIN ANALYZE SELECT * FROM impossible_travel_login 
ORDER BY timestamp DESC LIMIT 10;

-- Result: Index Scan using login_timestamp_desc_idx
-- Execution Time: 0.065 ms

Test 2: Country Case-Insensitive

EXPLAIN ANALYZE SELECT * FROM impossible_travel_login 
WHERE UPPER(country) = UPPER('italy');

-- Result: Bitmap Index Scan on login_country_upper_idx
-- Execution Time: 0.080 ms

Test 3: IP Exact Match

EXPLAIN ANALYZE SELECT * FROM impossible_travel_login 
WHERE ip = '192.168.1.1';

-- Result: Index Scan using login_ip_idx
-- Execution Time: 0.015 ms

📋 What Was NOT Done (Per Maintainer Requirements)

Based on feedback from @Lorygold on PRs #524, #531, #540:

🔬 Testing

  • Migration generated and applied successfully
  • All 3 indexes created in PostgreSQL
  • EXPLAIN ANALYZE confirms index usage (0.015-0.080ms)
  • 276 unit tests pass (0 failures related to this change)
  • No linter errors (models.py was already non-compliant on develop branch)
  • Comprehensive query analysis across entire codebase

📚 References

📝 Migration Details

File: 0023_login_login_timestamp_desc_idx_and_more.py
Operations:

  1. AddIndex on -timestamp (descending order)
  2. AddIndex on Upper(country) (case-insensitive functional index)
  3. AddIndex on ip (standard B-tree)

Note: This PR addresses Login model performance only. Alert model optimization (mentioned in #494) requires a different approach due to JSON field queries and should be handled in a separate PR.

@nishantxscooby
Copy link
Contributor Author

@Lorygold Could you please review this when you have a chance?

This PR addresses Part 1 of issue #494 (Login model indexes). I've added 3 query-aligned indexes based on comprehensive codebase analysis:

  1. Descending timestamp index - for order_by("-timestamp") queries (used in 10+ locations)
  2. Functional country index - for country__iexact lookups (case-insensitive)
  3. IP address index - for exact IP filtering

I followed your feedback from #524, #531, and #540 - skipping low-value fields like index and event_id.

All 276 tests pass, and EXPLAIN ANALYZE confirms the indexes are being used (0.015-0.080ms query times).

Thanks! 🙏

@Lorygold
Copy link
Contributor

Lorygold commented Feb 7, 2026

For next times: it's not necessary to open new PRs, you can work on the initial one and update it.
So, you can close the old PR: #540

Btw, now it's okay, thank you!

@lucaCigarini @eugenioseveri I think this PR can be merged

@eugenioseveri eugenioseveri merged commit 74e3a5a into certego:develop Feb 9, 2026
2 checks passed
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.

[PERFORMANCE] Backend: Missing Database Indexes Causing Slow Queries

3 participants