Skip to content

[Bug]: Nullable scalar result decoding is quadratic #3722

Description

@pymilvus-bot

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Nullable scalar result decoding is quadratic in PyMilvus 2.6.16, 2.6.17, and current master.

decode_range() calls decode_cell() for every logical row. For every valid nullable row, decode_cell() calculates physical_index() by scanning valid_data[:logical_index]. Ordinary scalar payloads use the logical index and do not use that physical index, so a result with N nullable scalar values performs O(N²) validity-mask work on one Python core.

The regression affects nullable BOOL, integer, floating-point, string/VARCHAR/TEXT, TIMESTAMPTZ, and GEOMETRY output fields. Nullable JSON and ARRAY decoding also performs the unnecessary physical-index calculation in the per-cell path.

The behavior entered in commit 7b8bb8af and was first released in PyMilvus 2.6.16. PyMilvus 2.6.15 used a bulk scalar slice followed by one validity pass.

Expected Behavior

Nullable scalar result decoding should be O(N): bulk-slice the scalar protobuf column, then apply valid_data once. Physical-index calculation should remain only in vector branches that use compact physical storage.

Steps/Code To Reproduce behavior

Construct a mocked Search response with:

- `nq=1`
- `top_k=100000`
- one output field: `VARCHAR(max_length=256, nullable=True)`
- 100,000 strings of length 256
- `valid_data=[True] * 100000`

Then construct the public search result through `MilvusClient.search()` and measure client-side result decoding.

Observed on master at `9f7fca59`:

- current decoder: 183.352 s
- linear bulk scalar decoder: 228.632-237.972 ms
- improvement: 770x-802x, about 99.88% lower latency

The repository benchmark added by the proposed fix is:

`tests/benchmark/test_search_bench.py::TestSearchBench::test_search_nullable_varchar_256_topk_100000`

Environment details

- Hardware/Software conditions: Linux x86_64
- Method of installation: source checkout
- PyMilvus version: master at `9f7fca59`; also reproduced in 2.6.16 and 2.6.17
- Python: 3.14.5
- protobuf: 5.29.6
- Milvus server: not required; benchmark isolates mocked client-side result construction

Anything else?

The proposed fix preserves physical-index handling for nullable dense and sparse vectors, adds a deterministic regression test for linear validity traversal, and adds the exact 100,000-row benchmark.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions