SQL Profiling and Performance Diagnostics
This project includes two complementary profiling mechanisms that enhance visibility into SQL query behavior and ORM performance:
- Performance Profiler (Hibernate Statistics) – "descending": trace how many requests domain level methods have generated.
- JDBC SQL Proxy Logging – trace what domain level method generated individual SQL queries
These tools can prove highly helpful during development and diagnostics to help identify performance bottlenecks and detect inefficient database access patterns.
Both mechanisms are opt-in and non-invasive.
Why is this useful?
Hibernate abstracts away SQL – which is great, until performance issues arise. But once they do, just enabling
org.hibernate.SQLlogs shows what SQL is executed, not who triggered it.
These tools make it possible to link domain methods to actual SQL queries played against the DB. Understanding who triggers which SQL, and how often, comes in as essential for: - Detecting N+1 query problems - Profiling slow queries - Understanding ORM caching behavior - Tracing code paths that result in SQL calls
> 1. Performance Profiler (Hibernate statistics)
>> Strategy
Collect and log high-level Hibernate metrics like:
- Number of SQL queries executed per transaction
- Second-level cache hits/misses
- Entity load/fetch count
This gives us a global view of ORM activity.
>> How it works
A Spring @Aspect is defined and wraps method execution (usually on service classes) to capture Hibernate metrics before and after method calls.
It uses:
- Hibernate SessionFactory.getStatistics()
- Java reflection to log method/class
- Execution time and query count before/after method call
The Aspect logs these different statistics, providing method-level performance snapshots.
>> Example output
PROFILING (Hibernate stats)--- Method CustomerQueryServiceImpl.findAllAccountByBu took 152 ms, triggered 8 SQL queries, 7 entities loaded, 5 collections loaded
>> Enabling and disabling
In app config file (application.yaml e.g.):
profiling:
performance:
enabled: true
logLinePrefix: "PROFILING (Hibernate stats)---"
>> Strengths/Limitations
✅ Shows cumulative ORM cost of high-level methods
✅ Exposes cache efficiency
✅ Helps detect query spam
❌ Doesn't show actual SQL
❌ No per-query granularity
> 2. JDBC SQL Profiling via datasource-proxy
>> Strategy
Intercept every actual SQL statement executed at JDBC level, and log:
- The SQL
- The execution time (ms)
- The Java class, method, and line number that triggered it
This is code-aware profiling: it bridges the gap between SQL and your business logic.
>> How it works
See DataSourceProxyConfig.java.
- A proxy wraps the
DataSourceusing [datasource-proxy] (https://github.com/ttddyy/datasource-proxy) - The proxy is registered as the primary
DataSource(via@Primary) - A custom
QueryExecutionListenerlogs details after each SQL execution - To avoid a circular dependency (Liquibase needs a DataSource early), an additional non-proxied
liquibaseDataSourceis defined
>> Required Maven dependency
<dependency>
<groupId>net.ttddyy</groupId>
<artifactId>datasource-proxy</artifactId>
<version>1.9</version>
</dependency>
>> Output example
PROFILING (dataproxy)--- SQL executed (11 ms) from [CustomerQueryServiceImpl:findAllAccountByBu:70]
SELECT * FROM customer WHERE region = 'EU'
>> Enabling and disabling
In app config file (application.yaml e.g.):
profiling:
sql:
enabled: true
logLinePrefix: "PROFILING (dataproxy)---"
>> Strengths/Limitations
✅ Logs every SQL
✅ Associates queries to the triggering code
✅ Measures latency per query
✅ Works across Hibernate, JPA, JdbcTemplate, etc.
❌ Cannot introspect ORM-level events (cache, flush, etc.)
❌ Log volume can be high
> 3. Summary Comparison
| Feature | Performance Profiler (Hibernate statistics) | SQL Proxy (datasource-proxy) |
|---|---|---|
| SQL visibility | ❌ No | ✅ Yes |
| Execution timing | ❌ No | ✅ Yes |
| Shows triggering class/method | ❌ No | ✅ Yes |
| ORM cache, flush, lazy loading info | ✅ Yes | ❌ No |
| Tracks total query counts | ✅ Yes | ❌ Not directly |
| Easily filtered in logs | ✅ Yes (log prefix customizable) | ✅ Yes (log prefix customizable) |
> 4. Final thoughts
These two tools operate at different layers but together give a complete view of:
- What SQL was executed
- Where in the code it was triggered
- How long it took
- What Hibernate was doing under the hood
Use them during feature development, refactoring, or performance tuning.