Skip to content

perf: reuse metrics evaluator within manifests#3655

Open
dossett wants to merge 1 commit into
apache:mainfrom
dossett:reuse-metrics-evaluator
Open

perf: reuse metrics evaluator within manifests#3655
dossett wants to merge 1 commit into
apache:mainfrom
dossett:reuse-metrics-evaluator

Conversation

@dossett

@dossett dossett commented Jul 14, 2026

Copy link
Copy Markdown

I used CODEX to analyze this problem and create this PR. I've reviewed the code and test and stand by them. This summary is written completely by a human (me) other than very light copy editing by an LLM.

Profiling with py-spy showed that a great deal of time was being spent constructing the _InclusiveMetricsEvaluator object. This object is used to interpret file statistics and determine whether a file might contain rows matching the scan predicate.

This PR does two things:

  • Allows reuse of the same object for different files within the same manifest
  • Lazily constructs the object so that it's only constructed if it's actually needed

CODEX summary follows:


Local scan planning applies Iceberg file metrics after partition filtering to determine whether each data file might contain matching rows. PyIceberg currently rebuilds the schema struct and rebinds the scan predicate every time that metrics evaluator is called. For manifests with many files, this repeats identical setup work and can dominate planning time.

This change reuses one _InclusiveMetricsEvaluator within each manifest task. The evaluator is initialized lazily when the first file survives partition filtering, then reused across that manifest's sequential entries. Each manifest receives a separate closure and evaluator, so the mutable file-metrics state is never shared across worker threads.

Performance

The focused benchmark evaluates 1,000 files from one manifest-shaped batch using a 102-column schema and a 66-leaf predicate. Results are the mean of three in-process runs:

Revision | Mean | Best -- | -- | -- main | 1.491 s | 1.467 s This PR | 0.105 s | 0.104 s

That is approximately 14.2x faster for the isolated metrics-evaluation hot path.

The benchmark includes evaluator construction and file-metrics evaluation, but excludes catalog access, manifest I/O, partition filtering, residual computation, and downstream data reads. It is not an end-to-end query-runtime claim.

Testing

  • Added coverage proving a callable constructs one evaluator and reuses it across files.
  • Added coverage proving separate callables receive separate evaluator instances.
  • Added coverage proving reused evaluators replace their mutable bounds and count state between files, including files with missing metrics.
  • Added a reproducible focused benchmark.
  • Planner and evaluator tests: 182 passed.
  • Full unit suite: 3,767 passed, 1,561 deselected.
  • All repository hooks pass, including Ruff, mypy, pydocstyle, codespell, and lockfile validation.

There are no API or result-semantics changes.

AI assistance

Codex assisted with implementation, test scaffolding, benchmark design, validation, and PR drafting.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant