Skip to content

perf(bigquery): [T1-2] zero-allocation column name lookup in FieldList.getIndex - #6

Open
lqiu96 wants to merge 1 commit into
mainfrom
perf/bq-t1-02-fieldlist-getindex
Open

lqiu96 wants to merge 1 commit into
mainfrom
perf/bq-t1-02-fieldlist-getindex

Conversation

@lqiu96

@lqiu96 lqiu96 commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Summary & Bottleneck

When callers access row values by column name via FieldValueList.get(String name), every cell lookup delegates to FieldList.getIndex(String name). Previously, FieldList backed nameIndex with a custom CaseInsensitiveMap subclass of HashMap that executed key.toString().toLowerCase() on every get(Object key) call.

  • Whenever a column name contained any uppercase character (such as CamelCase or UPPER_SNAKE_CASE), String.toLowerCase() allocated a new String and backing byte array on every cell read across every row ($O(\text{rows} \times \text{cols})$ allocations).
  • Even for all-lowercase column names, String.toLowerCase() scanned every character of the column name on every cell access and consulted Locale.getDefault().
  • In addition, new CaseInsensitiveMap() initialized the underlying HashMap with default capacity (16), causing repeated table resizing on wide schemas.

Changes

  • In java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FieldList.java:
    • Pre-size nameIndex using Maps.newHashMapWithExpectedSize(size * 2) and populate both the lowercase column name (name.toLowerCase(Locale.ROOT)) and the exact-case column name at FieldList construction time.
    • Preserve identical resolution semantics when case-insensitive collisions exist.
    • In getIndex(String name), probe nameIndex.get(name) first so exact-case and lowercase column names resolve in a single hash probe with zero character scanning and zero allocations, falling back to nameIndex.get(name.toLowerCase(Locale.ROOT)) only on a miss.
  • In java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldListTest.java:
    • Add unit test coverage in testGetIndexExactLowerAndMixedCase verifying exact-case, lowercase, mixed-case, and missing column name lookups.

Expected Impact

  • Eliminates $O(\text{rows} \times \text{cols})$ String and byte[] allocations when reading non-lowercase column names via FieldValueList.get(String).
  • Eliminates per-cell character scanning and Locale.getDefault() lookups on exact-case and lowercase column name hits.
  • Eliminates intermediate HashMap table resizing during FieldList construction for wide schemas.

Verification

  • Ran unit tests in FieldListTest, SchemaTest, and FieldValueListTest:
    mvn test -pl java-bigquery/google-cloud-bigquery -Dtest=FieldListTest,SchemaTest,FieldValueListTest

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