Optimize Azure Cosmos DB indexing, vector search cost, and consistency
Back to the AI-200 path
AI-200Chapter 11

Microsoft AI-200 Certification Study

Optimize Azure Cosmos DB indexing, vector search cost, and consistency

Turn production query patterns into selective range, composite, tuple, and vector indexes, measure RU efficiency, and choose consistency guarantees that preserve freshness without unnecessary cost.

Suggested study time: 115 minutes • Intermediate • Complete original rewrite with a concise version of every topic, assessment review, and guided performance lab

Neon Microsoft Certified AI-200 shield with Azure Cosmos DB indexing, vector search, RU optimization, and consistency symbols

1. Diagnose the production search problem before adding indexes

A semantic document platform can work well with a small development dataset and still miss its production target. Imagine millions of items containing metadata, extracted text, and embeddings generated by Azure OpenAI. Users combine keywords, date and type filters, and semantic ranking, and expect responses in under 100 milliseconds. In production, RU charges spike, latency grows, and fresh uploads sometimes disappear from immediate searches.

The likely causes are different but related: the default policy range-indexes every property, including large embedding arrays; required composite indexes are absent, so complex queries scan; and eventual consistency does not guarantee that the uploading user immediately reads the new item. The right response is to catalog query patterns, inspect query metrics, choose only the indexes those patterns need, and match consistency to each user journey.

  • Identify poorly performing filters, sorts, and vector queries.
  • Configure range and composite indexes for real access patterns.
  • Choose flat, quantizedFlat, or DiskANN from dataset and quality targets.
  • Balance read gains against write, storage, and transformation costs.
  • Select a consistency level that delivers required freshness at an acceptable RU price.

Topic summary

Production tuning starts with query evidence and freshness requirements, not with adding every possible index.

2. Understand automatic indexing, index families, and modes

A new for NoSQL container automatically indexes every property with range indexes. That makes early development convenient because almost any scalar filter can use an index, but every indexed path occupies storage and adds synchronous work to writes. Predictable AI workloads usually gain from replacing this broad default with a deliberate policy.

Index families and the query patterns they serve.
Index familyPrimary use
RangeEquality and range predicates, single-property ORDER BY, string functions, and IS_DEFINED.
CompositeORDER BY across multiple properties and common combinations of equality and range filters.
SpatialST_DISTANCE, ST_WITHIN, and ST_INTERSECTS for geographic data.
VectorSimilarity search through VectorDistance for embeddings.
TupleMultiple fields belonging to the same array element.
Full-textText search policies covered elsewhere in the AI-200 path.

Consistent mode updates indexes synchronously and is the normal choice when newly ingested items must be queryable. None disables secondary indexing and suits pure key-value point reads by id and partition key or temporary bulk-load designs. Lazy indexing is deprecated for new containers; existing uses should move to consistent mode.

Topic summary

Automatic indexing maximizes query coverage; a custom consistent policy reduces needless storage and write work.

3. Control included paths, excluded paths, and system properties

Paths describe precisely what enters an index. /* recursively includes scalar properties from the root, /property/? selects one scalar value, /array/[] covers every array element, and /nested/path/* covers descendants. When an included and excluded rule conflict, the more specific path wins, which makes broad exclusion plus narrow inclusion practical.

  • id and _ts remain indexed in consistent mode and cannot be disabled.
  • _etag is excluded by default and is rarely worth including.
  • A partition key other than /id is not automatically range-indexed; explicitly include it when queries filter on that property.
  • Exclude large content, binary payloads, raw metadata, and embedding arrays when they are stored but never filtered or sorted.
{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    { "path": "/tenantId/?" },
    { "path": "/documentType/?" },
    { "path": "/category/?" },
    { "path": "/uploadDate/?" }
  ],
  "excludedPaths": [
    { "path": "/*" },
    { "path": "/embedding/*" }
  ],
  "compositeIndexes": [[
    { "path": "/documentType", "order": "ascending" },
    { "path": "/uploadDate", "order": "descending" }
  ]],
  "vectorIndexes": [
    { "path": "/embedding", "type": "diskANN" }
  ]
}
Selective Azure Cosmos DB indexing policy routes metadata to range and composite indexes while embeddings use a vector index.
One policy can coordinate scalar, composite, and vector access while leaving unqueried payloads outside normal indexing.

Topic summary

Use an exclude-by-default policy when access patterns are stable, then include the partition key and every property actually used by queries.

4. Design range indexes for filters and string predicates

Range indexes support =, !=, >, <, >=, and <=, along with single-property sorting. They also support CONTAINS, STARTSWITH, ENDSWITH, StringEquals, and IS_DEFINED when the indexed property appears in the supported position. A query filtering documentType and uploadDate should have both paths indexed, otherwise RU consumption grows with scanned data rather than returned results.

Range indexes are the baseline for type, status, category, timestamps, scores, and numeric thresholds. They do not replace full-text indexes for linguistic retrieval and should not be applied to embedding arrays just because those arrays contain numbers.

Topic summary

Range indexes efficiently locate scalar values and intervals; reserve them for fields that participate in filters or simple sorting.

5. Match composite indexes to ORDER BY and multi-filter queries

A query ordering by two or more properties requires a composite index whose paths appear in the same sequence and direction. An index on relevanceScore DESC and uploadDate DESC also supports the complete opposite order on both paths, but not a mixed direction. A different sequence is a different index.

A useful optimization for a query that filters by documentType and sorts by uploadDate is to repeat the equality-filtered property in ORDER BY. The composite index can then satisfy both the fixed prefix and the ordered suffix.

SELECT * FROM c
WHERE c.documentType = 'pdf'
ORDER BY c.documentType ASC, c.uploadDate DESC

For filters on several properties, put equality predicates first and at most one range predicate last. If the query has two range conditions, can combine two composite indexes, each beginning with the shared equality fields and ending with one range field. Prioritize high-frequency, high-volume patterns rather than building dozens of indexes for rare cases.

Topic summary

Composite indexes are order-sensitive: equality paths form the prefix, one range path ends the definition, and multi-property sorting must match exactly.

6. Use tuple indexes and change policies safely

A tuple index keeps related fields from the same array element together. It is appropriate for document chunks with position and token count, tags with category and weight, or events with timestamp and type. Without tuple semantics, the engine cannot efficiently represent that multiple predicates must match the same array member.

{
  "includedPaths": [
    { "path": "/*" },
    { "path": "/chunks/[]/{position, tokens}/?" }
  ]
}

Every index increases write latency and RU consumption because consistent indexes are maintained during writes. Policy changes run as asynchronous transformations. New indexes help only after transformation completes; removed indexes stop serving queries immediately. When replacing an index, add the new definition, wait for 100% transformation, and only then remove the old one. Monitor progress in the Azure portal or supported SDK surfaces and schedule major transformations outside peak traffic.

Topic summary

Tuple indexes solve same-array-element filters; safe index replacement always follows add, wait, verify, then remove.

7. Select the right vector index for the search scope

Vector indexes accelerate VectorDistance while range and composite indexes serve metadata predicates. A container vector policy first defines each embedding path, element type, dimensions, and distance function. The indexing policy then assigns flat, quantizedFlat, or diskANN to that path.

Vector index decision guide.
TypeBehavior and limitTypical search scope
flatExact brute-force comparison; maximum 505 dimensions.Small candidate sets or cases that require 100% recall.
quantizedFlatCompressed brute-force vectors; maximum 4,096 dimensions and a small possible recall loss.Roughly 1,000 to 50,000 vectors per physical partition or heavily filtered searches.
diskANNApproximate nearest-neighbor structure from Microsoft Research; maximum 4,096 dimensions.More than about 50,000 vectors per physical partition, low latency, and RU efficiency.

quantizedFlat and diskANN need at least 1,000 vectors before their optimized structures become effective; below that threshold the service performs a full scan. A growing application can begin with flat and migrate after representative testing. Always exclude embedding paths from range indexing because vector queries use their dedicated index.

Decision flow compares flat, quantizedFlat, and DiskANN vector indexes by vector count, recall, latency, and RU cost.
The search scope after partition and metadata filters matters more than the total account size.

Topic summary

Choose a vector index from filtered vector count, dimensions, recall, latency, and RU targets; there is no universal default.

8. Tune vector construction and coordinate metadata filters

Most workloads should begin with service defaults. quantizationByteSize accepts 1–512 bytes: larger values retain more information but use more storage. For diskANN, indexingSearchListSize accepts 10–500 and defaults to 100; a larger construction list can improve recall while making index construction and vector ingestion more expensive.

{
  "vectorIndexes": [{
    "path": "/embedding",
    "type": "diskANN",
    "quantizationByteSize": 64,
    "indexingSearchListSize": 150
  }]
}

Combine the vector index with range or composite indexes on category, department, type, and date. Selective metadata predicates reduce the candidate set before or alongside similarity ranking, which can sharply lower RU consumption. The container vector policy is a design-time commitment: changing dimensions, data type, or distance function generally requires a new compatible policy/container and data migration. float16 uses roughly half the storage of float32 with a usually small quality impact; int8 and uint8 require measured quantization choices. Cosine is common for text embeddings.

Topic summary

Tune construction parameters only from measured recall and latency, and design immutable vector dimensions, type, and distance function before production.

9. Measure query efficiency and discover missing indexes

Query metrics turn a slow-query report into evidence. Index utilization reveals how much work used an index, retrieved document count shows how many items storage produced for evaluation, and output document count shows how many survived. Low utilization or a large retrieved-to-output ratio commonly indicates a scan, a missing path, or a missing composite index.

from azure.cosmos import CosmosClient

metrics = {}
def response_hook(headers, _):
    metrics["query"] = headers.get("x-ms-documentdb-query-metrics", "")
    metrics["ru"] = headers.get("x-ms-request-charge", "")

items = list(container.query_items(
    query="SELECT * FROM c WHERE c.documentType = @type ORDER BY c.uploadDate DESC",
    parameters=[{"name": "@type", "value": "pdf"}],
    populate_query_metrics=True,
    response_hook=response_hook
))

print(metrics["query"])
print(f'{metrics["ru"]} RUs')

Capture x-ms-request-charge with the query metrics, change one policy assumption at a time, wait for index transformation, and rerun the same test. A TOP clause can reduce returned results but does not repair a missing index. Compare representative percentiles and query shapes, not a single convenient request.

Topic summary

Use index utilization, retrieved/output counts, and request charge to prove which index change reduces work.

10. Balance RU cost for read-heavy and write-heavy workloads

Indexed reads tend to consume RUs in proportion to the result set, while scans grow with data volume. Yet each extra path and composite index consumes storage and write RUs. Read-heavy search, reporting, and dashboard workloads usually justify broader coverage; high-volume ingestion, frequent embedding updates, streaming, and batch-write workloads favor fewer indexes.

  • Catalog WHERE, ORDER BY, aggregates, property combinations, direction, and execution frequency.
  • Include the five to ten query patterns that deliver the largest measured benefit.
  • Keep large display-only text, raw metadata, and vectors out of range indexing.
  • Test realistic cardinality, skew, partition distribution, and production-scale vector counts.
  • Compare both read and write RU before declaring an index cost-effective.

Synthetic uniform data can hide hot categories and uneven partitions. Load production-like distributions, execute representative queries, compare policies, and choose from measured workload cost rather than theoretical coverage.

Topic summary

The best policy minimizes total workload cost: frequent reads can justify extra indexes, while frequent writes reward selectivity.

11. Compare all five consistency levels and their RU implications

Consistency guarantees and read cost.
LevelGuarantee and common fitRelative read RU
StrongLinearizable latest committed read; regulated or correctness-critical data. Not supported with multiple write regions.
Bounded stalenessLag limited by K versions or T time; predictable cross-region bound for single-write-region accounts.
SessionRead-your-writes within a client session; the practical default for user-facing applications.
Consistent prefixWrites are never observed out of order, although data can be stale; logs and ordered streams.
EventualNo freshness or ordering promise; highest throughput and lowest latency for analytics and background work.

Strong and bounded staleness reads consult two replicas, so their read throughput per RU is roughly half that of session, consistent prefix, or eventual reads. Operation-level write RU is the same across levels, but strong consistency waits for global majority replication and therefore increases write latency. All weaker levels commit to a local majority before asynchronous cross-region replication.

Consistency spectrum moves from strong freshness and higher read cost to eventual availability, throughput, and lower latency.
Choose the weakest guarantee that still satisfies the business interaction.

Topic summary

Consistency is a freshness, latency, availability, and cost decision; stronger is not automatically better.

12. Preserve read-your-writes with session tokens and monitor PBS

Session consistency fits document and vector search when an uploader must immediately find new content. The token represents progress within a partition. One SDK client manages tokens automatically, but distributed services must pass the write operation token to the later read. Other sessions may briefly observe stale data.

from azure.cosmos import CosmosClient, ConsistencyLevel

client = CosmosClient(
    url=endpoint,
    credential=credential,
    consistency_level=ConsistencyLevel.Session
)

session = {}
def capture(headers, _):
    session["token"] = headers.get("x-ms-session-token", "")

container.create_item(body=document, response_hook=capture)

results = container.query_items(
    query="SELECT * FROM c WHERE c.category = @category",
    parameters=[{"name": "@category", "value": "proposals"}],
    session_token=session.get("token")
)

Separate client instances can apply stronger consistency to critical reads and eventual consistency to background analytics. In multi-region systems, strong writes wait for the farthest regions and cannot coexist with multiple write regions; bounded staleness is best aligned with one write region; session and weaker levels confirm locally and replicate asynchronously. Probabilistically Bounded Staleness (PBS) metrics in show how often eventual reads actually return current data and help decide whether weaker consistency is safe.

Topic summary

Pass session tokens across service boundaries for immediate self-visibility, and use PBS evidence before weakening user-facing consistency.

13. Guided lab: compare vector indexes with production-like data

The source exercise proposes a 30-minute comparison of flat, quantizedFlat, and diskANN. It requires an Azure subscription with deployment permissions, , the latest Azure CLI, and Python 3.12 or later. Use a disposable resource group and remove it after recording the results.

  1. Download or create starter files and parameterize the deployment.
  2. Deploy an for NoSQL account with vector search enabled.
  3. Create three otherwise identical containers that differ only by vector index type.
  4. Load identical documents and embeddings into every container.
  5. Build Python functions that run the same filtered and unfiltered VectorDistance queries.
  6. Expose comparative latency, request charge, and top-result overlap in a small Flask application.
  7. Repeat after at least 1,000 vectors and with realistic metadata selectivity.
  8. Record recall against flat, median and tail latency, RU, and index storage; then choose the index that meets the explicit target.

Do not compare indexes with different data, partitions, query vectors, or filters. Warm-up effects and small collections can distort results, so repeat each scenario and report the distribution rather than the fastest run.

Topic summary

A fair vector-index benchmark holds data and queries constant and compares recall, latency, RU, and storage at realistic scale.

14. Assessment review and reasoning

  1. Filter by documentType and sort by uploadDate DESC: use a composite index beginning with documentType ASC and ending with uploadDate DESC.
  2. About 500,000 embeddings per partition with acceptable approximation: diskANN is the scale-oriented choice.
  3. Embeddings used only for vector similarity: exclude their path from range indexing and keep a dedicated vector index.
  4. Users must immediately see their own uploads: use session consistency and propagate the write session token to the read.
  5. Low index utilization plus a high retrieved/output ratio: the query is scanning; inspect its predicates and add the appropriate range or composite index.

The distractors reveal common mistakes: independent range indexes do not satisfy a multi-property sort, disabling all indexing sacrifices unrelated queries, extra throughput does not create a freshness guarantee, and TOP does not fix inefficient filtering.

Topic summary

Exam answers follow the query shape, vector scale, storage behavior, freshness guarantee, and observed metric—not a generic performance slogan.

15. Final checklist and official references

  • Inventory query patterns before writing the policy.
  • Index the partition key when an exclude-by-default policy still queries it.
  • Use range, composite, spatial, tuple, and vector indexes only for their supported patterns.
  • Exclude embeddings from range indexes and measure the vector search scope.
  • Add replacement indexes before removing the old definitions.
  • Validate RU and latency with realistic distributions and index transformation complete.
  • Use session consistency for immediate self-visibility and weaker levels where staleness is acceptable.

Official Microsoft references

  1. Indexing policies in
  2. Manage indexing policies in for NoSQL
  3. Vector search in for NoSQL
  4. Optimize request cost in
  5. Consistency levels in
  6. Manage consistency levels

Topic summary

Efficient search combines selective indexing, measured vector choices, safe transformations, and the least costly consistency guarantee that meets the user experience.