Skip to content

Try a larger hibernate.jdbc.batch_size for the GTFS import #27

Description

@aaronbrethorst

Follow-up to #22 / #26.

Context

After enabling reWriteBatchedInserts=true in #26 the WMATA import dropped from ~10 min to ~4m26s on a fresh docker compose stack. The block-write phase (the hot loop in DbWriter.actuallyWriteData at transitclock/src/main/java/org/transitclock/gtfs/DbWriter.java:129) is still the dominant cost — ~266s of the 266s total.

Observation

With hibernate.jdbc.batch_size=50 set in docs/examples/postgres_hibernate.cfg.xml, Postgres log_statement=mod shows the cascade-saved tables arriving as 32-row multi-row INSERTs, not 50-row. Examples from the import:

  • TravelTimesForStopPaths (9 cols): $1…$288 → 32 rows
  • Trips (17 cols): $1…$544 → 32 rows
  • Block_to_Trip_joinTable (7 cols): $1…$224 → 32 rows

PG's only hard ceiling is 32,767 bound parameters per statement (~3,400 rows for a 9-col table, ~1,900 for a 17-col table), so the 32-row chunks are nowhere near it. The most likely explanations are some interaction between Hibernate's batch_size, DbWriter's session.flush() cadence (transitclock.db.batchSize = 100), and pgjdbc's batch rewriter — but I haven't actually traced it.

Suggested experiment

  1. Bump hibernate.jdbc.batch_size in docs/examples/postgres_hibernate.cfg.xml to 100, then 200.
  2. Re-run ./quickstart.sh --gtfs-zip /path/to/wmata.zip --avl-url … from a clean state.
  3. Compare the DbWriter — Finished writing GTFS data to database. Took N msec line, plus per-1000-block timings.
  4. Confirm the multi-row INSERT shape with docker compose logs db | grep 'insert into Trips' (after enabling log_statement=mod).

If the chunk size in PG actually grows to 100+, expect a meaningful per-batch fixed-cost reduction (parse, bind, network). If it stays pinned at 32, that tells us the limit is somewhere else (probably in pgjdbc's rewriteBatchedInserts chunking or in DbWriter's flush cadence) and the next investigation is to lift that.

Notes

  • The current value of 50 was chosen so each transitclock.db.batchSize=100 flush ships a whole number of JDBC batches; if we bump batch_size, consider whether transitclock.db.batchSize should track it.
  • Live AVL/AD writes via DataDbLogger also use hibernate.jdbc.batch_size. A larger batch is probably fine for them too (those rows are tiny), but worth a quick smoke under load before merging.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions