# Azure AI Search Over-provisioned

> Azure AI Search services running more replica-partition units than their SLA floor are flagged when average query volume stays below 0.1 QPS over 30 days with at least 7 days of coverage and throttling under 1%. Savings equal the per-unit monthly cost times the excess units above the 1, 2, or 3-unit floor.

Source: https://zop.dev/integrations/azure/recommendations/azure-ai-search-over-provisioned
Updated: 2026-08-19

---

## Which search units sit above the SLA floor

- resource.UnitCount: replicas × partitions (search units). Rule skips services at the 1-unit floor (UnitCount \<= 1).
- resource.Type must equal ai-search.
- availability-SLA tag zopnight:search-read-sla (ParsedTags): value-dependent scale-down floor per Azure's documented replica requirements (searchSLATargetUnits): "read" or generic truthy ("true"/"1"/"yes") → hold 2 units (searchReadSLAUnits, the query/read SLA); "read-write"/"readwrite" → hold 3 units (searchReadWriteSLAUnits, the index-update/read-write SLA, which requires 3+ replicas, not 2); absent/unrecognized → 1×1 floor. If UnitCount \<= targetUnits there is nothing to reclaim => abstain.
- SearchQueriesPerSecond.Average: average QPS over 30 days. Fires only when present and Average \< 0.1.
- SearchQueriesPerSecond.MaxCoverageDays >= 7 (MinMaxCoverageDays): guards freshly provisioned near-zero traffic.
- ThrottledSearchQueriesPercentage.Average: throttling guard; present and Average >= 1.0% => do not fire (capacity is in use).

## Gates that must align before flagging

```text
fires when all gates align: UnitCount > targetUnits (1, 2 with the read-SLA tag, or 3 with the read-write-SLA tag) AND SearchQueriesPerSecond present AND Average < 0.1 QPS AND MaxCoverageDays >= 7 AND (ThrottledSearchQueriesPercentage absent OR Average < 1.0%) AND cost > 0.
```

## Why per-unit cost is the bill split by units

Every search unit bills at the same per-search-unit-hour rate, so per-unit cost is the service's own monthly cost split across its units: perSU = cost / UnitCount; scaling to the target floor reclaims savings = perSU × (UnitCount − targetUnits), defensively capped at cost. With UnitCount ≤ target floor or unknown cost the rule abstains (returns nil) rather than emit $0. The scale-down stays recommendation-only (Azure AI Search cannot be stopped, replica/partition scaling is slow and affects the SLA), but the dollar figure is now concrete (no fabricated fraction, no $0 advisory).

## Scaling replicas and partitions back down

1. Azure Portal → your Search service → Settings → Scale
2. Review query volume (Monitoring → Metrics → Search Queries Per Second) and latency before changing capacity
3. Reduce replicas and/or partitions (floor is 1 replica × 1 partition)
4. Note: scaling is not instantaneous and 2+ replicas are required for the read SLA (3+ for read-write), so keep enough for your availability target

## Query rate paired with a throttling guard

SearchQueriesPerSecond + ThrottledSearchQueriesPercentage (30d lookback each)
