Skip to content

Reduce redundant snapshot reads and default-option parsing overhead in PK planning #305

Closed

Description

@wangyong9999

Problem

PK point reads incur two avoidable planning costs:

  1. PrimaryKeyIndexBatchScan::CreatePlan() loads the snapshot after creating its data plan, even when the underlying scan already holds that same snapshot. Remote storage therefore sees another open/read and JSON parse.
  2. OptionsUtils::GetOptionalValueFromMap() handles an absent setting by constructing a formatted NotExist status and discarding it. CoreOptions::FromMap() requests many defaults, so concurrent reader construction repeatedly pays for error formatting and iostream/locale work on a normal path.

This is a performance improvement, not a reported result-correctness bug. The two costs are independent; neither requires a process-wide cache.

Reproduction

Baseline: apache/paimon-cpp ded7cfb84005a6315f4778253411dc78f7fa4cb3. Proposed implementation: #303, 0345e430afea1829b856e0b2ac2ea4b90cc071e7.

  • Snapshot: run FileFormat/PrimaryKeySortedIndexInteTest.HistoricalSnapshotsMixedFilesAndDisabledIndex/* with the tracking filesystem assertions in perf(read): reduce snapshot and option parsing overhead #303. For snapshots 2, 3 and 5, both Parquet and ORC open the selected snapshot twice before the change, once afterward, with unchanged result checks. The negative control uses the same test with the unmodified implementation.
  • Configuration: concurrently call CoreOptions::FromMap({{"file.format", "parquet"}}) in a loop (2,000 calls per worker; 1/8/32/64 workers released from a common start barrier). Compile the caller and core_options.cpp with C++17, -O2 -Wall, using the original or modified OptionsUtils header and otherwise identical dependencies. Sum completed calls and divide by elapsed wall time. Two repetitions were made, reversing the baseline/fixed execution order.

Measured effect

Configuration-only microbenchmark on Linux x86_64 (aggregate calls/s, observed range of two runs):

Workers Before After
1 14,783–14,943 164,082–165,259
8 11,643–12,118 1,184,340–1,255,940
32 11,466–11,484 1,161,670–1,289,440
64 11,962–12,042 1,073,330–1,189,250

These short microbenchmark runs identify the parsing cost; their speedup is not query throughput or a capacity claim.

In a separate application-level PK read test (3 servers, 96 logical CPUs and 25 Gbit/s networking each, SSD-backed HDFS, 12M rows, 8 fixed buckets, uniform successful-key lookup returning a 1 KiB payload), changing only the option-parsing implementation at C128 increased successful throughput from 2,585 to 2,804 QPS (+8.5%); AVG fell from 49.5 to 45.7 ms and P99 from 107.7 to 88.8 ms. Each version used two 60-second runs, the same snapshot/file layout and placement, and the same admission limit. Results include admission errors (434 before, 411 after); this does not establish error-free serving capacity. Per-run variation exists; raw before/after details are in #303.

Expected outcome

  • Reuse the data plan's snapshot for index planning when IDs match; retain the existing load path otherwise. Do not change snapshot discovery or freshness.
  • Return an empty optional without constructing an error when an optional key is absent. Preserve required-key errors, invalid-value errors and explicitly supplied values.
  • Keep the regression tests and document the measured effects and limitations.

Implementation: #303. Close this issue when that PR is merged.

Activity

  1. wangyong9999 commented on Sep 10, 2026

    @wangyong9999
    ContributorAuthor

    Post-merge validation of the option-parsing change

    A later controlled local-filesystem test isolated the OptionsUtils part of #303 from the snapshot-reuse change.

    Test shape:

    • Linux x86_64, one process, 32 physical / 64 logical CPUs.
    • PK table with 2.1M rows and 22 uncompressed Parquet files.
    • Fixed snapshot, identical wide projection and lookup keys.
    • Four alternating rounds at C1 and C8.
    • The compared builds differed only by the option-parsing implementation.
    Concurrency Before AVG After AVG Change
    C1 4.060 ms 3.658 ms -9.9%
    C8 5.399 ms 3.896 ms -27.8%

    An on-CPU perf profile (-F 999 -g --call-graph dwarf) attributed approximately 5.34% of the relevant point-read stack to CoreOptions::FromMap before the change and 1.34% afterward. The missing-option NotExist formatting and locale-related subtree disappeared. An independent post-fix C64 saturation profile reported 1.36% CoreOptions stack coverage, confirming that option parsing was no longer a dominant cost.

    This profile result is specific to the measured request path and is not an additive CPU or capacity claim. At C64 the host was already CPU-saturated and snapshot/manifest planning, Parquet page reads, and materialization dominated the remaining samples.

    Semantics were rechecked for present values, missing required values, missing values with defaults, invalid conversion, and explicitly empty strings. The merged implementation preserves those outcomes while avoiding error construction for an expected absent optional value.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions