3. Performance Facts
“More than half of application performance
bottlenecks originate in the database”
AppDynamics - http://www.appdynamics.com/database/
5. Poor man’s JDBC
• High response time
• Low throughput
Photo by Amit Patel CC BY 2.0 https://www.flickr.com/photos/amitp/6069412747/
6. State of the art JDBC
• Low response time
• High throughput
Photo by zoetnet CC BY 2.0 https://www.flickr.com/photos/zoetnet/14288129197/
7. Response time
• connection acquisition time
• statements submission time
• statements execution time
• result set fetching time
• idle time prior to releasing the database connection
𝑇 = 𝑡 𝑎𝑐𝑞 + 𝑡 𝑟𝑒𝑞 + 𝑡 𝑒𝑥𝑒𝑐 + 𝑡 𝑟𝑒𝑠 + 𝑡𝑖𝑑𝑙𝑒
20. Oracle Statement batching
• For Statement and CallableStatement,
the Oracle JDBC Driver doesn’t actually support batching,
each statement being executed separately.
21. MySQL Statement batching
• By default, the MySQL JDBC driver doesn’t send the batched
statements in a single request.
• The rewriteBatchedStatements connection property
adds all batched statements to a String buffer.
30. SQL Server server-side statement caching
• Execution plan cache
• Parameter sniffing
• Force recompile
SELECT *
FROM task
WHERE status = ?
OPTION(RECOMPILE);
31. PostgreSQL server-side statement caching
• Prior to 9.2 – execution plan caching
• 9.2 – optimization and planning are deferred
• The prepareThreshold connection property
32. MySQL server-side statement caching
• No execution plan cache
• Since Connector/J 5.0.5 PreparedStatements are only
emulated
• To activate server-side prepared statements:
• useServerPrepStmts
• cachePrepStmts
35. Oracle implicit client-side statement caching
• Can be disabled on a per statement basis
if (statement.isPoolable()) {
statement.setPoolable(false);
}
36. Oracle explicit client-side statement caching
• Caches both metadata and execution state with data
OracleConnection oracleConnection =
(OracleConnection) connection;
oracleConnection.setExplicitCachingEnabled(true);
oracleConnection.setStatementCacheSize(cacheSize);
39. PostgreSQL Server client-side statement caching
• PostgreSQL JDBC Driver 9.4-1202 makes client-side
statement connection-bound instead of statement-bound
• Configurable:
• preparedStatementCacheQueries (default is 256)
• preparedStatementCacheSizeMiB (default is 5MB)
• Statement.setPoolable(false) is not supported
40. MySQL Server client-side statement caching
• Configurable:
• cachePrepStmts (default is false)
Required for server-side statement caching as well
• prepStmtCacheSize (default is 25)
• prepStmtCacheSqlLimit (default is 256)
• Statement.setPoolable(false) works for client-side
statements only
42. Oracle ResultSet fetch size
• Default fetch size is 10
• Oracle 10i and 11g JDBC Driver maximum ResultSet size
memory preallocation
• VARCHAR2(4000) – allocates 8000 bytes (even for 1 character)
• Memory buffers are recycled only when using Statement caching
• Oracle 12c allocates memory on demand
• VARCHAR2(4000) – 15 bytes + the actual row column size
43. SQL Server ResultSet fetch size
• Adaptive buffering
• Only for the default read-only and forward-only ResultSet
• Updatable cursors use fixed data blocks
44. PostgreSQL ResultSet fetch size
• Fetch all – one database roundtrip
• Custom fetch size – database cursor
45. MySQL ResultSet fetch size
• Fetch all – one database roundtrip
• Streaming – only one record at a time
47. ResultSet size
• Avoid fetching data that is not required
• Hibernate addresses the max-size vendor-specific SQL
statement syntax
48. SQL:2008 ResultSet size limit
• Oracle 12c, SQL Server 2012 and PostgreSQL 8.4
SELECT
pc.id AS pc_id, p.title AS p_title
FROM post_comment pc
INNER JOIN post p ON p.id = pc.post_id
ORDER BY pc_id
OFFSET ? ROWS
FETCH FIRST (?) ROWS ONLY;
49. Oracle ResultSet size limit
SELECT *
FROM (
SELECT
pc.id AS pc_id, p.title AS p_title
FROM post_comment pc
INNER JOIN post p ON p.id = pc.post_id
ORDER BY pc_id
)
WHERE ROWNUM <= ?
50. SQL Server ResultSet size limit
SELECT
TOP (?) pc.id AS pc_id, p.title AS p_title
FROM post_comment pc
INNER JOIN post p ON p.id = pc.post_id
ORDER BY pc_id
51. PostgreSQL and MySQL ResultSet size limit
SELECT
pc.id AS pc_id, p.title AS p_title
FROM post_comment pc
INNER JOIN post p ON p.id = pc.post_id
ORDER BY pc_id
LIMIT ?
52. Statement max rows
• Vendor-independent syntax
• Might not influence the execution plan
• According to the documentation:
“If the limit is exceeded, the excess rows are silently dropped.”
statement.setMaxRows(maxRows);
53. Max size: 1 million vs 100 rows
Fetch all Fetch max rows Fetch limit
0
500
1000
1500
2000
2500
3000
3500
4000
4500
5000
Time(ms)
DB_A DB_B DB_C DB_D
54. Fetching too many columns
• Fetching all column (ORM tools)
SELECT *
FROM post_comment pc
INNER JOIN post p ON p.id = pc.post_id
INNER JOIN post_details pd ON p.id = pd.id
55. Fetching too many columns
• Fetching a custom SQL projection
SELECT pc.version
FROM post_comment pc
INNER JOIN post p ON p.id = pc.post_id
INNER JOIN post_details pd ON p.id = pd.id
56. Fetching too many columns performance impact
All columns Custom projection
0
5
10
15
20
25
30
Time(ms)
DB_A DB_B DB_C DB_D
57. Processing Logic
• Hibernate defers connection acquisition
• Release connection as soon as possible
𝑇 = 𝑡 𝑎𝑐𝑞 + 𝑡 𝑟𝑒𝑞 + 𝑡 𝑒𝑥𝑒𝑐 + 𝑡 𝑟𝑒𝑠 + 𝑡𝑖𝑑𝑙𝑒