Lesson 23 / 25

Performance Checklist

Diagnose and tune JPA performance with logging, statistics and batching.

Most ORM slowness is visible in the SQL

A practical checklist for JPA performance: look at the SQL (org.hibernate.SQL logging, or a datasource proxy that counts queries per request); make all associations LAZY and fetch per use case; eliminate N+1 with join fetch, entity graphs or batch fetching; use DTO projections for read-heavy screens; enable JDBC batching (hibernate.jdbc.batch_size, order_inserts, order_updates) and use SEQUENCE IDs so inserts can batch; flush and clear in long batch jobs; add database indexes for foreign keys and frequent filters (Hibernate does not create them for you in production); avoid open-in-view; keep transactions short; size the connection pool sensibly (more is not faster beyond the database's capacity); use keyset pagination for deep pages; and enable Hibernate statistics in non-production environments to count queries, entity loads and cache hits. Finally, measure with realistic data volumes: a query plan that is fine with 100 rows can be a disaster with 10 million.

Diagnostics and batching configuration

Make SQL visible and let inserts and updates batch.

spring:
  jpa:
    open-in-view: false
    properties:
      hibernate:
        jdbc.batch_size: 50
        order_inserts: true
        order_updates: true
        default_batch_fetch_size: 50
        generate_statistics: true          # dev/test only: query and entity counts per session
        query.fail_on_pagination_over_collection_fetch: true   # catch in-memory pagination
  datasource:
    hikari:
      maximum-pool-size: 20

logging:
  level:
    org.hibernate.SQL: debug
    org.hibernate.stat: debug

# also: create indexes in migrations for foreign keys and common filters, e.g.
# CREATE INDEX idx_order_lines_order_id ON order_lines(order_id);
# CREATE INDEX idx_orders_status_placed_at ON orders(status, placed_at);

A car dashboard

SQL logs and Hibernate statistics are the dashboard gauges. Without them you only notice the problem when the engine overheats in production; with them you see the query count climbing during a test drive.

Quick check: Which setting allows Hibernate to send many INSERT statements in one JDBC batch?

  • spring.jpa.open-in-view=true
  • hibernate.jdbc.batch_size (with SEQUENCE IDs)
  • ddl-auto=update
  • FetchType.EAGER
Answer

hibernate.jdbc.batch_size (with SEQUENCE IDs) — JDBC batching groups statements; IDENTITY IDs would prevent insert batching.