Hibernate can log a warning for every query slower than a configured number of milliseconds. Which setting turns that on, what exactly does the reported time measure, and how does it differ from the database server's own slow-query log?
answer
- hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS
- logs WARN to org.hibernate.SQL_SLOW
- client-side timing: includes network + queueing + waits
- DB slow log = server-side execution only
- pair with use_sql_comments to bridge both logs
basics
~20 sSet hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS to a millisecond threshold. Hibernate then logs each slower statement to the org.hibernate.SQL_SLOW category with its elapsed time, measured client-side around JDBC execution — so it includes network and server queueing, unlike the database's own log.
solid answer
~50 sThe property is `hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS` (a positive millisecond value). It installs a session event listener that times each JDBC statement execution and emits a WARN line to the **`org.hibernate.SQL_SLOW`** logger containing the elapsed milliseconds and the SQL text. What it measures is the **client-side** duration of the JDBC execute call: connection round trip, server queueing, lock waiting and server execution all included. The database's slow-query log measures **server-side** execution only, after the statement reached the engine. So the two disagree in informative ways: a statement that is slow in Hibernate but fast in the database log is spending its time in the network, in a saturated connection, or waiting; a statement slow in both is genuinely expensive to execute. Use it when you want app-side attribution — it costs almost nothing, is always on, and unlike DEBUG statement logging it produces output proportional to your problems rather than to your traffic.
code
properties · 5 lineshibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=300
hibernate.use_sql_comments=true
logger.org.hibernate.SQL=INFO
logger.org.hibernate.SQL_SLOW=WARNgo deeper
Know that Hibernate has a millisecond threshold setting that warns about slow statements, and that it logs under its own category.
State the property name and the SQL_SLOW category, and explain that the timing is client-side around JDBC execution.
Contrast it with the database's own slow log and statement statistics, use SQL comments to correlate the two, and pick a threshold that is a tripwire rather than a firehose.
Position it inside an observability budget: always-on cheap signals versus on-demand expensive ones, per-service thresholds, and the fact that per-occurrence thresholds structurally miss the many-fast-executions pathology.
## The setting `hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=<millis>` (exposed in the API as an `AvailableSettings` constant) enables Hibernate's built-in slow-statement detector. Set it to, say, 300 and every JDBC statement whose execution exceeds 300 ms produces a WARN log event on the category `org.hibernate.SQL_SLOW`, shaped roughly as `SlowQuery: 412 milliseconds. SQL: 'select ...'`. Mechanically it works through the session event listener mechanism: Hibernate already has hooks around statement execution (`jdbcExecuteStatementStart` / `jdbcExecuteStatementEnd`), and this setting registers a listener that timestamps them and compares the delta to the threshold. Because the timing is only taken when the listener is installed, the overhead when the feature is off is nil, and when on it is a nanosecond-scale timestamp per statement. ## What the number includes The measured interval is the JDBC execute call as seen from inside the application. That interval contains: - serialising the statement and parameters to the wire, - network latency to the database, both directions, - time the statement spent queued on the server, including waiting for a lock or for other sessions, - actual execution on the server, - returning the first results. It does **not** include time spent waiting to obtain a connection from the pool (that happens earlier), nor time Hibernate later spends materialising entities from the result set, nor the cost of a lazy association loaded afterwards. So it isolates 'this one statement was slow', not 'this request was slow'. ## Versus the database's own slow-query log Database engines have their own slow-statement capture — a duration threshold that logs statements taking longer than a configured time, or a statement-statistics view that aggregates total and mean time per normalised statement. Differences that matter: - **Vantage point.** The engine measures its own execution; Hibernate measures the round trip. Subtracting one from the other is a direct estimate of network plus queueing. - **Attribution.** The engine sees SQL text with no idea which application code produced it. Hibernate sees it in your application log, on your thread, with your MDC/correlation id — and if you also enable `hibernate.use_sql_comments`, the HQL or entity operation that generated it is embedded in the statement text and shows up in *both* logs. That comment is the cheapest bridge between the two worlds. - **Coverage.** The engine catches statements from every client, including migrations, ad-hoc sessions and other services sharing the database. Hibernate only sees its own. - **Aggregation.** A threshold log is per-occurrence and misses the pathology of a fast statement executed fifty thousand times. Server-side statement statistics aggregate by normalised text and expose exactly that. Hibernate's `QueryStatistics` (with `generate_statistics`) plays the same aggregating role on the application side. ## Choosing a threshold Too low and you flood the log during any incident, at exactly the moment logging pressure hurts most; too high and you never see the thing that is degrading p99. A workable approach is to set it near the upper end of what you consider acceptable for a single statement in that service — often a few hundred milliseconds for an interactive path — and then treat any recurring entry as a bug rather than noise. Different services deserve different values; a reporting job legitimately runs statements for seconds. ## How it fits the wider toolkit - **`org.hibernate.SQL` at DEBUG**: everything, always, expensive. Use for local diagnosis and short production windows. - **`org.hibernate.SQL_SLOW` via the threshold**: only the pathological, cheap enough to leave on permanently. Use as a standing production tripwire. - **`generate_statistics` + `QueryStatistics`**: aggregate counts and times per query, catching the many-fast-executions case the threshold cannot see. - **Database-side statement statistics**: the ground truth across all clients, and the place to rank by total time rather than per-execution time. A sensible production baseline is: statement logging off, `use_sql_comments` on, slow-query threshold on with a service-appropriate value, and the database's own aggregated statistics available for ranking. That gives you attribution when something is slow without paying per-statement log cost when everything is fine.
- A statement appears repeatedly in Hibernate's slow-query log but never in the database's slow-statement log. What do you investigate?The gap is everything outside server execution: network latency, TLS renegotiation, a saturated database connection, or time the statement spent waiting on a lock before the engine counted it as executing. Check connection-pool saturation, host-to-host latency, and lock waiting on the affected table. It is a symptom of the environment or of contention, not of a bad execution plan.
saying these in an interview costs you the question
- Assuming the reported time is pure database execution time, and hunting for a bad plan when the delay is network or lock waiting
- Believing the threshold captures a statement that runs in 2 ms fifty thousand times — it will never fire
- Setting the threshold so low it becomes a second copy of full statement logging
- Thinking it replaces the database's slow-query log, which also covers every other client of that database
- Expecting it to include the time spent waiting for a pooled connection