Skip to content

feat(bigquery): skip job creation for ARROW query_and_wait results - #18799

Open
ohmayr wants to merge 2 commits into
mainfrom
feat/bigquery-arrow-job-creation-optional
Open

ohmayr wants to merge 2 commits into
mainfrom
feat/bigquery-arrow-job-creation-optional

Conversation

@ohmayr

@ohmayr ohmayr commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Before, query_and_wait(query_results_format="ARROW") always created a job unless the caller set client.default_job_creation_mode, so small Arrow queries paid about 200 ms for a job they didn't need. Arrow callers want low latency, so ARROW queries now default to JOB_CREATION_OPTIONAL, which is what createQueryArrowStream() in the Node.js client already does.

This changes behavior for existing ARROW callers (Beta since 3.44.0): results that fit in the first response now come back with RowIterator.job_id set to None. location and query_id are still set. To always get a job, set default_job_creation_mode="JOB_CREATION_REQUIRED" on the client or use client.query().

  • query_and_wait() sends jobCreationMode=JOB_CREATION_OPTIONAL when query_results_format is ARROW and the client doesn't set default_job_creation_mode. A client-level mode still wins.
  • Multi-page and long-running ARROW queries still get a job, since BigQuery creates one when rows remain. ARROW queries that need jobs.insert (for example, with a destination table) also still create a job.
  • Queries without ARROW are unchanged.
  • The query_results_format and default_job_creation_mode docstrings describe the new default and how to opt out.
  • Tests: unit tests for the ARROW default, a client-level mode taking precedence, non-ARROW queries sending no mode, and the jobs.insert fallback. Ran the unit suite and tests/system/test_arrow.py against BigQuery. A live single-page ARROW query returned job_id=None, while a multi-page ARROW query, a non-ARROW query and an ARROW query with JOB_CREATION_REQUIRED on the client each returned a job.

Callers who pass query_results_format="ARROW" want low latency, so
query_and_wait() now sends jobCreationMode=JOB_CREATION_OPTIONAL for
them unless the client sets default_job_creation_mode. Single-page
results skip creating a job (about 200 ms faster), so RowIterator.job_id
is None for them. Multi-page results still create a job.

Callers who need a job can set default_job_creation_mode to
JOB_CREATION_REQUIRED or use client.query(). Queries without ARROW are
unchanged. This matches createQueryArrowStream() in the Node.js client.
@ohmayr
ohmayr requested review from a team as code owners October 21, 2026 19:01
@ohmayr
ohmayr requested review from julianxu-goog and tswast and removed request for a team and julianxu-goog October 21, 2026 19:01

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the query_and_wait method to automatically set the jobCreationMode to JOB_CREATION_OPTIONAL when the query results format is set to ARROW and no default mode is specified on the client. It also updates the corresponding docstrings and adds unit tests to verify this behavior. Feedback is provided regarding the handling of the query_results_format Enum parameter, advising that type annotations and input handling for raw string representations should be consistent across all related API methods rather than handled selectively.

request_body["maxResults"] = page_size or max_results
if client.default_job_creation_mode:
request_body["jobCreationMode"] = client.default_job_creation_mode
elif query_results_format == enums.QueryResultsFormat.ARROW:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When supporting raw string representations for an Enum parameter like query_results_format, we must ensure that type annotations and input handling are consistent across all related API methods. We should not selectively support or normalize raw string inputs in only a subset of methods. If we want to support string inputs (including case-insensitive comparisons), this handling should be applied uniformly across all related methods rather than as a localized change here.

References
  1. When a parameter accepts an Enum, ensure its type annotations and input handling are consistent across all related API methods. Do not selectively support raw string representations in only a subset of these methods.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't add any string handling. It's the same == enums.QueryResultsFormat.ARROW check query_and_wait() already uses a few lines up, and QueryResultsFormat is a str enum, so it behaves the same as the existing check.

The unit_noextras session runs without google-cloud-bigquery-storage,
so query_and_wait() raised before building the request. Patch
_arrow_query._check_dependencies like the other ARROW tests do, since
these tests only check the request.

This branch has not been deployed

No deployments
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