Skip to content

Size a Deployment

A workflow for turning a dataset shape and workload into an index shortlist and a resource estimate. For index tuning and general performance questions, refer to the Performance FAQ. For build/search parameters and schema construction, refer to Use Indexes.

Run this interactively

The sizing skill in KDB.AI Skills for Claude Code and Codex works through this same workflow and bundles an estimator script that computes the RAM, disk, and VRAM figures from your own rows, dimensions, and index choice.

Index choice, update pattern, filters, concurrency, and search requirements all change how much RAM, disk, VRAM, and CPU the same dataset needs. Rows and dimensions alone size a raw-vector footprint, nothing more.

Work through this order:

  1. Establish the workload.
  2. Shortlist two or three viable index configurations, CPU or GPU, rather than picking one from row count alone.
  3. Estimate RAM, disk, and VRAM for each option.
  4. Decide whether to partition the table.
  5. Validate the shortlist with a focused proof of concept before procurement.

Establish the workload

The two inputs you need for a numerical estimate are row count (or total data size, if you track bytes instead) and embedding dimensions. Everything else refines the shortlist:

  • Row count or data size. Use the current row count, or table.info() for an existing table. If you only track a data volume (a total size, or a size-per-day and a retention window), convert it to rows using the vector column size (dims × bytes per value). This is an upper bound unless you know the actual per-row metadata size.
  • Embedding dimensions. From the index's dims, the embedding model documentation, or the length of one vector.
  • Search type. Exact recall, high-recall approximate, or compression-first. Range/radius search needs qFlat; other indexes serve top-N search.
  • Update pattern. One-time/batch load versus streaming inserts, updates, and deletes. This decides whether CAGRA is viable, covered below.
  • Vector column type. float32s unless you know the column is float64s. qFlat and qHnsw require float32s and reject float64s. Flat, HNSW, IVF, IVF-PQ, and CAGRA accept both.
  • Concurrency and deployment. Expected simultaneous searches, available CPU cores or GPU, and whether the ingestion client and KDB.AI server are co-located. Refer to Size CPU cores and workers below for the license implications of NUM_WRK.

Index shortlist

Row count is a starting point, not the whole answer. Cross-check against Use Indexes for the full comparison.

Rows Start with (CPU) Consider CAGRA (GPU) when Change when
0–100K flat or qFlat Rarely worth it at this scale Use hnsw when query latency or volume makes exhaustive search unsuitable
100K–1M hnsw; qHnsw when RAM is constrained Batched or high-concurrency top-N search and a GPU is already available Use flat only when exact recall is required and measured latency is acceptable
1M–10M qHnsw or ivfpq Mostly static data with batched queries, and GPU throughput beyond CPU HNSW is needed Prefer qHnsw for update-friendly graph search; prefer IVF-PQ when compression is the priority
10M+ qHnsw or ivfpq Same as above, once CPU HNSW throughput is the limiter Choose by update pattern, recall, compression, and measured latency

Row count doesn't gate CAGRA, and neither does simply owning a GPU. What matters is whether the workload has the shape CAGRA needs: mostly static data, batched or sufficiently concurrent top-N search, a supported GPU (Ampere or newer), and enough single-card VRAM for the index, search workspace, and a measured build peak. Frequent updates or deletes can make CAGRA's rebuild cost unacceptable, and that rules it out regardless of scale. Refer to Nvidia cuVS/CAGRA integration.

Estimate RAM, disk, and VRAM

These figures can shift across KDB.AI/cuVS versions, so validate them against a representative proof of concept before procurement.

  • Raw vector footprint: four bytes per value for a stored float32s column, eight for float64s (excludes metadata). Refer to vector column type support for how this interacts with each index's internal representation.
  • Fixed index RAM is a per-worker figure, and what counts toward it varies by index. For Flat, HNSW, and IVF, it's the full index vectors plus a structure on top (a graph for HNSW, centroids for IVF). qHNSW only carries index vectors at mmapLevel=0; at the default level 1 and at level 2 it's graph-only, no vector copy. IVF-PQ never carries full vectors at all, only its compressed codes, centroids, and PQ codebook. qFlat has no fixed RAM floor. Whatever the figure comes out to, multiply it by the number of active NUM_WRK workers, since each can load its own copy of the resident index state.
  • On-disk indexes still use RAM under load. The low fixed floor quoted for qFlat/qHnsw is a minimum, and actual usage typically runs above it. Refer to the on-disk memory note in the Performance FAQ, and measure settled memory after representative queries.
  • Persisted disk is the raw vector column plus the index structure. Refer to vector storage per index for which indexes duplicate vectors into a separate index file versus store a compressed representation. Excludes metadata, filesystem overhead, replicas, and backups.
  • CAGRA index VRAM is the resident index payload. nvidia-smi reports more than that figure, so add CUDA/cuVS runtime and search-workspace overhead (roughly 1.8× the index vectors is a documented starting point). Leave headroom for build peak too; it runs higher than steady state, and depends on insert batch size.
  • Client and server RAM are separate, unless co-located. Refer to the client/server memory Q&A in the Performance FAQ.

Validate any estimate with table.info() for actual rows and persisted size, and session.process_info() / session.system_info() for worker memory and system headroom.

Partitioning

Partitioning is a table-layout choice you make with partition_column at create_table. It's orthogonal to index choice, so a partitioned table still carries one of the shortlisted indexes. Don't partition by default or purely because the dataset is large. Raise it when the workload shows a natural filter key, the chosen index's full-volume footprint strains resources, or you need retention/archival.

  • Index compatibility is a hard constraint. Partitioning supports only Flat, qFlat, HNSW, qHNSW, sparse, and TSS indexes. A partitioned table can't carry IVF, IVF-PQ, or CAGRA. If the workload needs IVF-PQ compression or CAGRA GPU search, size it as a single non-partitioned table instead.
  • Pruning only pays off when the partition column is in the query filter. If queries don't filter on it, every query scans every partition, and partitioning adds cost without benefit.
  • Partitioning is per table. Each table sets its own partition_column independently. There's no shared database-wide partition domain to reconcile across tables.
  • Size RAM and disk differently for a partitioned table. Only the partitions a query selects load into memory (resident indexes per partition, mmap indexes the same way), so run the RAM estimate at the row count of the window a query actually touches. Disk still has to cover the full retained row count. For multi-year data those two numbers can differ by orders of magnitude.

Size CPU cores and workers

Resolve NUM_WRK and THREADS from expected active work, not from rows and dimensions. Refer to Parallel Processing for how the two interact.

Multi-worker bands below need a commercial license

The free KDB-X Community Edition license runs a single worker only (plus a 24-core, 16-qIPC-connection cap).

Workload KDB.AI CPU starting point Initial configuration
Evaluation, development, or serial queries 4 cores NUM_WRK=1, THREADS=4
Light production with 1–2 active searches 8 cores NUM_WRK=1–2, normally THREADS=4
Moderate production with 3–4 active searches 16 cores NUM_WRK=2–4, normally THREADS=4
Higher concurrency with roughly 5–8 active searches 24 cores NUM_WRK=4–8; start with THREADS=2–4 within core and RAM limits
Heavy ingestion into one table 8–16 cores NUM_WRK=1 (extra workers don't parallelize inserts into a single table); compare THREADS=4 and 8
Parallel ingestion into different tables ~4 cores per active stream Add workers for independently active tables within core and RAM limits

Validate these bands before applying them:

  • NUM_WRK × THREADS should stay within your licensed or allocated core count, but treat that number as a ceiling on contention rather than something to reach for its own sake. Throughput can plateau or regress past a certain point for a given index and machine, so raise either value incrementally and measure as you go.
  • More workers multiply fixed index RAM, and only genuinely concurrent requests exercise more than one worker. Refer to Parallel Processing for both.
  • Prefer qIPC over REST for throughput-sensitive deployments: REST serializes and deserializes every payload, and qIPC doesn't.

Size GPU VRAM for CAGRA

CAGRA VRAM works the same way: figures here are a starting point, and the real number comes from measuring your own workload. The VRAM planning table gives index-payload and build-peak figures for 1M, 10M, and 100M vector datasets, plus the build-algorithm trade-off (IVF_PQ versus nn_descent) behind them.

A CAGRA index must fit on a single GPU. Confirm the card's architecture (Ampere or newer) and VRAM headroom before committing to it as an option.

Validate before procurement

Build the shortlisted configurations on a representative sample with realistic filters, concurrency, and ingestion pattern before committing to hardware. Compare at least the nearest smaller and larger worker/thread split, and repeat performance measurements at least three times. One run can mislead you either way.

For operational configuration, refer to the Performance FAQ and Server Setup FAQ.