| Table | Index | Query |
precedent_objects | idx_precedent_payer | WHERE tenant_id = $1 AND payer = $2 |
precedent_objects | idx_precedent_denial_type | WHERE tenant_id = $1 AND denial_type = $2 |
precedent_objects | idx_precedent_loc | WHERE tenant_id = $1 AND loc = $2 |
precedent_objects | idx_precedent_status | WHERE tenant_id = $1 AND status = $2 |
precedent_objects | idx_precedent_cluster | WHERE tenant_id = $1 AND cluster_id = $2 |
appeals | idx_appeal_status | WHERE tenant_id = $1 AND status = $2 |
payer_plans | idx_payer_plan_state | WHERE state = $1 AND payer_name = $2 AND plan_year = $3 |
marketplace_clusters | idx_cluster_payer | WHERE payer = $1 AND denial_type = $2 AND loc = $3 |
credit_ledger | idx_ledger_event | WHERE event_type = $1 AND status = $2 |
Definition pattern:
CREATE INDEX idx_table_field ON table_name(tenant_id, field) WHERE status != 'Archived';
Performance expectation: <10ms with index
Tier 3: Timeline/Range Queries (DESC Indexes)
Use case: "Most recent N items" queries
| Table | Index | Query |
precedent_objects | idx_precedent_last_validated DESC | Find outdated (not validated in 6 months) |
precedent_audit_log | idx_audit_precedent (precedent_id, timestamp DESC) | Get full timeline for precedent |
appeals | idx_appeal_created_at DESC | List recent appeals |
appeals | idx_appeal_submitted_at DESC | List recently submitted appeals |
credit_ledger | idx_ledger_posted_at DESC | Transaction history (balance timeline) |
payer_plans | idx_payer_plan_reviewed DESC | Find outdated policies |
Definition pattern:
CREATE INDEX idx_table_field_desc ON table_name(tenant_id, field DESC);
Example query:
-- Find all precedents not reviewed in 1 year
SELECT precedent_name, last_validated_date
FROM precedent_objects
WHERE tenant_id = $1 AND last_validated_date < CURRENT_DATE - INTERVAL '1 year'
ORDER BY last_validated_date ASC
LIMIT 20;
Performance expectation: <15ms with reverse index
Tier 4: JSONB Searches (GIN Indexes)
Use case: Search within flexible JSONB fields
| Table | Index | Query |
precedent_objects | idx_evidence_kit_gin | Search evidence_kit for specific requirement |
precedent_objects | idx_traceability_gin | Search traceability_ledger for actions |
payer_plans | idx_coverage_data_gin | Find plans requiring prior auth |
marketplace_clusters | idx_top_evidence_gin | Search evidence types by cluster |
Definition pattern:
CREATE INDEX idx_table_field_gin ON table_name USING GIN(jsonb_column);
Example queries:
-- Find all plans requiring prior auth for IOP
SELECT payer_name, plan_year
FROM payer_plans
WHERE coverage_data -> 'behavioral_health' -> 'iop' ->> 'requires_prior_auth' = 'true';
-- Find precedents with evidence_score="Strong" in evidence_kit
SELECT precedent_name
FROM precedent_objects
WHERE evidence_kit @> '{"strength": "strong"}';
Performance expectation: <20ms for JSONB searches on 10K rows
Composite Index Strategy
Use composite (multi-column) indexes for common query combinations:
-- Multi-field searches common enough to warrant composite index
CREATE INDEX idx_precedent_payer_denial_loc ON precedent_objects(
tenant_id, -- Always first (tenant isolation)
payer, -- Filter 1
denial_type, -- Filter 2
loc -- Filter 3
);
-- Query: WHERE tenant_id = $1 AND payer = $2 AND denial_type = $3 AND loc = $4
-- Time-range queries
CREATE INDEX idx_appeal_tenant_created_desc ON appeals(
tenant_id,
created_at DESC -- Allows "ORDER BY created_at DESC" without post-sort
);
-- Contribution scoring lookups
CREATE INDEX idx_contribution_tenant_score ON contribution_scores(
tenant_id,
total_score DESC -- Rank contributors
);
Rule: Composite indexes must have tenant_id first (for safety) and frequently-grouped columns in order of selectivity (most selective first).
Index Coverage for Common Queries
Query: Browse Library (Payer/Denial Type/LOC Filter)
SELECT FROM precedent_objects
WHERE tenant_id = $1 AND payer = $2 AND denial_type = $3 AND loc = $4
ORDER BY created_at DESC
LIMIT 25;
Indexes used:
idx_precedent_payer_denial_loc(tenant_id, payer, denial_type, loc)
idx_precedent_created_at DESC (for ORDER BY)
Expected time: <10ms
Query: Compliance Audit (SUD Data Access)
SELECT user_id, event_type, timestamp
FROM precedent_audit_log
WHERE tenant_id = $1 AND precedent_id IN (
SELECT id FROM precedent_objects WHERE data_origin_type = 'SUD'
)
ORDER BY timestamp DESC
LIMIT 100;
Indexes used:
idx_audit_tenant(tenant_id, timestamp DESC) (for outer query)
idx_precedent_data_origin(data_origin_type) (for subquery)
Expected time: <50ms (multi-step query)
Query: Credit Balance (Sum All Transactions)
SELECT SUM(amount) AS balance
FROM credit_ledger
WHERE tenant_id = $1 AND status = 'posted';
Indexes used:
idx_ledger_tenant(tenant_id, posted_at DESC) or idx_ledger_status(status, posted_at DESC)
Postgres optimizer picks best
Expected time: ~30–50ms (sum requires full table scan, but filtered to tenant)
Optimization: Cache balance in application layer (recompute on credit events, not on every query)
Query: Timeline/Versioning (Get All Versions)
SELECT version_number, changed_at, changed_by, change_reason
FROM precedent_version_history
WHERE precedent_id = $1 AND tenant_id = $2
ORDER BY version_number DESC;
Indexes used:
idx_version_precedent(precedent_id, version_number DESC)
Expected time: <5ms (small result set for single precedent)
Performance Expectations
| Query Pattern | Expected Time | Index Used |
Tenant isolation (WHERE tenant_id = $1) | <5ms | Composite index with tenant_id first |
Exact match 1 field (WHERE payer = $2) | <5ms | Single-field B-tree |
Exact match 3 fields (WHERE payer = $2 AND denial_type = $3 AND loc = $4) | <10ms | Composite B-tree |
Range + sort (WHERE created_at > X ORDER BY created_at DESC) | <15ms | Reverse (DESC) index |
Recent N items (WHERE status = 'Draft' ORDER BY created_at DESC LIMIT 10) | <10ms | Composite index on (status, created_at DESC) |
JSONB search (WHERE evidence_kit @> '{...}') | <20ms | GIN index on JSONB column |
Sum/Aggregate (SUM(amount) WHERE tenant_id = $1) | ~50ms | Index on tenant_id helps filtering, not aggregation |
| Full-table scan (no WHERE) | 100ms–1s | None (avoid in production) |