Skip to content

Commit 06966ba

Browse files
armenzgJesse-Box
authored andcommitted
dev(agents): Guidance on options and slow DB queries (#103059)
Changes included: * Do not suggest a default value when using `options.get()` * When filtering on columns, check that there's a composite index
1 parent d0b2f88 commit 06966ba

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

AGENTS.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,22 @@ class MyPermission(SentryPermission):
319319
}
320320
```
321321

322+
### Options System
323+
324+
Sentry uses a centralized options system where all options are registered in `src/sentry/options/defaults.py` with required default values.
325+
326+
```python
327+
# CORRECT: options.get() without default - registered default is used
328+
from sentry import options
329+
330+
batch_size = options.get("deletions.group-hash-metadata.batch-size")
331+
332+
# WRONG: Redundant default value
333+
batch_size = options.get("deletions.group-hash-metadata.batch-size", 1000)
334+
```
335+
336+
**Important**: Never suggest adding a default value to `options.get()` calls. All options are registered via `register()` in `defaults.py` which requires a default value. The options system will always return the registered default if no value is set, making a second default parameter redundant and potentially inconsistent.
337+
322338
### Logging Pattern
323339

324340
```python
@@ -394,6 +410,61 @@ class MultiProducer:
394410
4. Add indexes for queries on 1M+ row tables
395411
5. Use `db_index=True` or `db_index_together`
396412

413+
#### Composite Index Strategy: Match Your Query Patterns
414+
415+
**Critical Rule**: When writing a query that filters on multiple columns simultaneously, you MUST verify that a composite index exists covering those columns in the filter order.
416+
417+
**How to Identify When You Need a Composite Index:**
418+
419+
1. **Look for Multi-Column Filters**: Any query using multiple columns in `.filter()` or `WHERE` clause
420+
2. **Check Index Coverage**: Verify the model's `Meta.indexes` includes those columns
421+
3. **Consider Query Order**: Index column order should match the most selective filters first
422+
423+
**Common Patterns Requiring Composite Indexes:**
424+
425+
```python
426+
# NEEDS COMPOSITE INDEX: Filtering on foreign_key_id AND id
427+
Model.objects.filter(
428+
foreign_key_id__in=ids, # First column
429+
id__gt=last_id # Second column
430+
)[:batch_size]
431+
# Required: Index(fields=["foreign_key", "id"])
432+
433+
# NEEDS COMPOSITE INDEX: Status + timestamp range queries
434+
Model.objects.filter(
435+
status="open", # First column
436+
created_at__gte=start # Second column
437+
)
438+
# Required: Index(fields=["status", "created_at"])
439+
440+
# NEEDS COMPOSITE INDEX: Org + project + type lookups
441+
Model.objects.filter(
442+
organization_id=org_id, # First column
443+
project_id=proj_id, # Second column
444+
type=event_type # Third column
445+
)
446+
# Required: Index(fields=["organization", "project", "type"])
447+
```
448+
449+
**How to Check if Index Exists:**
450+
451+
1. Read the model file: Check the `Meta` class for `indexes = [...]`
452+
2. Single foreign key gets auto-index, but **NOT** when combined with other filters
453+
3. If you filter on FK + another column, you need explicit composite index
454+
455+
**Red Flags to Watch For:**
456+
457+
- Query uses `column1__in=[...]` AND `column2__gt/lt/gte/lte`
458+
- Query filters on FK relationship PLUS primary key or timestamp
459+
- Pagination queries combining filters with cursor-based `id__gt`
460+
- Large IN clauses combined with range filters
461+
462+
**When in Doubt:**
463+
464+
1. Check production query performance in Sentry issues (slow query alerts)
465+
2. Run `EXPLAIN ANALYZE` on similar queries against production-sized data
466+
3. Add the composite index if table has 1M+ rows and query runs in loops/batches
467+
397468
## Anti-Patterns (NEVER DO)
398469

399470
### Backend

0 commit comments

Comments
 (0)