Questions
1 of 13
1Why does Qdrant recommend disabling indexing (or raising the indexing threshold) during a large bulk import, then re-enabling it afterward?
2What is the purpose of the indexing_threshold setting, and how does it affect small versus large collections differently?
3How does GPU-accelerated indexing change the economics of re-indexing a large, frequently-updated collection?
4What is incremental HNSW indexing, and why does it matter for upsert-heavy workloads?
5Your Qdrant search endpoint's p50 latency looks fine, but p99 latency is very high. What are the most likely causes to investigate first?
6How would you reduce query latency for a collection that must remain on-disk due to its size, without moving the whole collection into RAM?
7What is the effect of increasing the number of search threads/parallelism on a single node with limited CPU cores?
8How would you benchmark whether a proposed quantization configuration is worth the accuracy trade-off for your workload?
9What's the difference between scaling Qdrant vertically (bigger node) and horizontally (more shards/nodes), and when does horizontal scaling stop paying off?
10Two teams store the same 50-million-vector collection - one keeps it fully in memory, one on disk with quantization. What operational differences should each expect?
11Why can moving the payload storage engine on-disk versus in-memory have a bigger impact on filtered-search latency than the vector storage location?
12How would you decide, for a specific collection, whether to enable quantization with rescoring versus simply moving vectors on-disk without quantization?
13What memory overhead does the HNSW graph itself add on top of the raw vector data, and why does that matter when planning RAM for an in-memory collection?
01 / 13

Why does Qdrant recommend disabling indexing (or raising the indexing threshold) during a large bulk import, then re-enabling it afterward?

Bulk-load raw vectors first, build the graph once at the end

Building an HNSW graph incrementally is far more expensive per point than building it once over a batch. Each incremental insert has to run a graph search to find the insertion neighborhood, apply the diversity heuristic, wire new edges, and potentially rewire the neighbors' edges if they exceed m. That work is done point by point, with poor locality and repeated graph traversals. When you instead load all the raw vectors first and then build the index over the whole batch, the build can process points in a more cache-friendly order, the graph is constructed once instead of being repeatedly repaired, and the work is parallelizable across threads and segments. The rule of thumb is that bulk-loading with indexing disabled and indexing once at the end can be several times faster than incremental indexing during the load, and the gap grows with collection size.

The mechanism is the optimizer's indexing_threshold. When a segment's point count is below the threshold, the optimizer skips building an HNSW graph for it and queries fall back to a brute-force scan over that segment. Above the threshold, the optimizer builds the graph. So the standard bulk-load procedure is: raise indexing_threshold to a value larger than the total number of points you are about to load, perform the load, then lower indexing_threshold back to its normal value. That triggers a single indexing pass over the consolidated data. The same logic applies to memmap_threshold, which controls when a segment is moved to disk - raising it during the load keeps segments in RAM, which is faster if they fit, and lowering it afterward moves cold data to disk. There is a second reason to disable indexing during a load: if indexing is running concurrently, the optimizer is competing with the ingest path for CPU and I/O, so both the load and any concurrent queries get slower. Deferring the index removes that contention entirely.

  1. 1

    Incremental insert cost: one graph search plus edge wiring plus possible neighbor rewiring per point.

  2. 2

    Bulk build cost: one pass over the batch, with better locality and more parallelism.

  3. 3

    Set indexing_threshold above the total load size, load, then lower it to trigger a single build.

  4. 4

    Same pattern applies to memmap_threshold if you want to control when segments move to disk.

  5. 5

    Queries during the load will use brute-force search on unindexed segments, which is slow but still correct - plan for a degraded search window.

The trade-off is ingest throughput against search quality during the load. While indexing is deferred, every segment is unindexed, so queries fall back to a linear scan. That is fine for a background migration or an initial load with no live traffic, but it is not acceptable if you are bulk-loading into a production collection that is serving users. In that case you either load in bounded batches (so only a fraction of the data is unindexed at any time), or you load into a new collection and swap an alias at the end. The common mistake is leaving the default indexing_threshold in place during a multi-million-point bulk load, which causes the optimizer to constantly build and merge segments, slowing both the load and any concurrent queries. The second mistake is forgetting to lower the threshold afterward - the collection looks fine because queries work, but they are all doing brute-force scans, and latency scales linearly with collection size. The third mistake is assuming that disabling indexing means writes are not durable. They are - they are in the WAL and in segments; the only thing missing is the graph. The alternative to the threshold-tuning approach is the two-collection swap: build a new collection with the final config, load it, then atomically move an alias. That is the safest pattern for production because it avoids any window where the live collection is unindexed. Version note: the exact field names (indexing_threshold, memmap_threshold) and their defaults have changed across releases, and in some versions the thresholds are interpreted per-segment rather than per-collection - verify on your version.

javascript

Version-dependent: in recent Qdrant releases the optimizer thresholds have been reworked and their defaults differ. Some versions expose an explicit way to disable indexing entirely for a period, and the interaction between indexing_threshold, memmap_threshold, and max_optimization_threads has changed. If you are running a large migration, benchmark the load on your version with your data rather than assuming a fixed speedup from the pattern.

Difficulty: 6/10
Topics: Optimizer, Bulk Indexing, Index Configuration

Scenario Questions

0-2 years experience
  1. 1

    You load 2M points with default thresholds and the load takes hours. Explain what the optimizer is doing and how raising indexing_threshold would change it.

  2. 2

    A teammate forgets to lower indexing_threshold after a load. Explain what the collection's search performance looks like and how you would detect it.

2-5 years experience
  1. 1

    You need to load 50M points into a collection that serves live traffic. Walk through how you would structure the load so search latency stays within SLO.

  2. 2

    You lower indexing_threshold after a load and the optimizer takes longer than expected. Diagnose the likely causes and propose changes to speed it up.

5-8 years experience
  1. 1

    Design a zero-downtime migration from a 1-shard collection to a new collection with different HNSW and quantization settings, including how you validate quality before cutover.

  2. 2

    You have a nightly job that appends 5M points to a 500M-point collection. Design an indexing strategy that keeps ingest fast without leaving the collection unindexed for the next day's queries.

8+ years experience
  1. 1

    Derive the cost of incremental HNSW insertion versus bulk build as a function of graph degree, batch size, and cache behavior. Where does the model predict the crossover point?

  2. 2

    You must design an ingest pipeline that accepts 10k writes per second continuously while maintaining a fully indexed collection at all times. Describe the architecture and the trade-offs versus the deferred-indexing approach.

Follow-up Questions

  • How would you perform a large bulk load into a production collection that must keep serving live queries, without degrading search latency during the load?
  • What signals tell you the optimizer has finished indexing after you lower the threshold, and how would you automate the transition in a migration script?