Optimizing Index Performance

1. Selecting Appropriate Pod Type

WorkloadPod Type
Large index, low QPSs1
Balancedp1
High QPS / low latencyp2

2. Configuring Pod Size

SymptomAction
High index_fullnessUpgrade pod size or add shards
Slow queries with selective filterUpgrade size; more memory
High write latencyLarger size or more shards

3. Setting Optimal Replica Count

Example: Estimate Replicas

# target 1500 QPS on p1.x1 (~100 QPS each)
required_replicas = math.ceil(1500 / 100)  # 15
pc.configure_index("docs", replicas=15)
RuleDetail
Linear QPS scalingReplicas ~= target_QPS / single_pod_QPS
Cost linearReplicas multiply pod cost

4. Tuning Batch Sizes

OpRecommended Batch
Upsert @ 1536d100
Fetch1000 IDs
Delete by ID1000

5. Implementing Connection Pooling

ClientMechanism
Python RESTpool_threads param
Python gRPCSingle channel, reuse
Node.jsUnderlying fetch keep-alive

6. Using Async Operations

Example: Async Upsert

from pinecone import PineconeAsyncio
import asyncio

async def upsert_all(batches):
    async with PineconeAsyncio(api_key="...") as pc:
        async with pc.IndexAsyncio(name="docs") as idx:
            await asyncio.gather(*(idx.upsert(vectors=b) for b in batches))

7. Optimizing Metadata Filtering

TipEffect
Pre-bucket numbersLower cardinality = faster
Selective indexing (pod)Skip non-filtered fields
Avoid wide $inSlow on 1000+ values

8. Caching Query Results

Example: Redis Cache

import hashlib, json, redis

r = redis.Redis()
def cached_query(qv, top_k, ns):
    key = "q:" + hashlib.sha256(
        json.dumps([qv, top_k, ns]).encode()).hexdigest()
    if (v := r.get(key)): return json.loads(v)
    res = index.query(vector=qv, top_k=top_k, namespace=ns)
    r.set(key, json.dumps(res), ex=300)
    return res

9. Monitoring Query Latency

SourceMetric
Pinecone consolep50/p95/p99 latency
Client-sideWrap calls with timer
APM (Datadog, NewRelic)End-to-end latency

10. Reducing Vector Dimensions

MethodTradeoff
Matryoshka (truncate)Small accuracy loss
PCALarger loss; needs training
Quantization (int8)4× storage savings

11. Understanding Throughput Limits

Index TypeThroughput
p1.x1~100 QPS
p2.x1~200 QPS
ServerlessScales with traffic, plan-dependent RU/s

12. Profiling Client Library Overhead

Example: Profile

import time

def timed(fn, *args, **kw):
    t = time.perf_counter()
    res = fn(*args, **kw)
    print(f"{fn.__name__}: {(time.perf_counter()-t)*1000:.1f}ms")
    return res

timed(index.query, vector=qv, top_k=10)