# Performance Checklist — Hibernate / JPA

Source: https://www.skillbyai.com/en/hibernate-jpa/p-performance

> 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.

```yaml
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.

**Quiz:** Which setting allows Hibernate to send many INSERT statements in one JDBC batch?

- [ ] spring.jpa.open-in-view=true
- [x] 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.
