SIMPLE_SQL_QUERY_MONITOR
Runtime N+1 query detection. Records executed queries and identifies patterns that suggest N+1 problems. Enable during development/testing to catch performance issues before production.
Development Tool
Query monitoring adds overhead. Enable it during development and testing to detect N+1 patterns, then disable in production. Use eager loading to fix detected issues.
Enable/Disable
db.enable_query_monitor
Start recording queries. All subsequent queries via
db.query are tracked.db.disable_query_monitor
Stop recording and clear all recorded data.
db.query_monitor: detachable SIMPLE_SQL_QUERY_MONITOR
Access the active monitor (Void if disabled).
Configuration
set_threshold (a_count: INTEGER)
Set warning threshold. A query pattern executed more than this many times triggers a warning. Default is 5.
threshold: INTEGER
Current warning threshold.
Recording
record_query (a_sql: READABLE_STRING_8)
Record a query execution. Called automatically by
db.query when monitoring is enabled.reset
Clear all recorded queries and warnings. Use between test cases.
Analysis
has_warnings: BOOLEAN
Were any N+1 patterns detected?
warnings: ARRAYED_LIST [TUPLE [pattern: STRING_8; exec_count: INTEGER]]
List of detected N+1 patterns with execution counts.
report: STRING_8
Human-readable report of all detected patterns.
query_count: INTEGER
Total number of queries recorded.
Examples
Basic Usage
do
-- Enable monitoring
db.enable_query_monitor
-- Run your code that might have N+1 issues
load_documents_with_folders
-- Check for problems
if attached db.query_monitor as monitor then
if monitor.has_warnings then
print ("N+1 WARNING:%N")
print (monitor.report)
else
print ("No N+1 patterns detected. " + monitor.query_count.out + " queries total.%N")
end
end
-- Disable when done
db.disable_query_monitor
end
In Test Cases
class TEST_DOCUMENT_LOADING
feature -- Tests
test_no_n_plus_1_when_loading_documents
local
docs: SIMPLE_SQL_RESULT
do
db.enable_query_monitor
if attached db.query_monitor as mon then
mon.set_threshold (3) -- Stricter for tests
end
-- Operation under test
docs := document_service.load_all_with_folders
-- Assert no N+1
if attached db.query_monitor as mon then
assert ("no N+1 queries", not mon.has_warnings)
if mon.has_warnings then
print (mon.report)
end
end
db.disable_query_monitor
end
end
Detecting the Problem
-- This code has an N+1 problem:
across db.select_from ("documents").execute as doc loop
-- Query per document!
folder := db.select_from ("folders")
.where ("id = ?", doc.integer_value ("folder_id"))
.execute.first
end
-- Query monitor output:
-- N+1 Query Warning Report
-- ========================
-- Pattern: SELECT * FROM folders WHERE id = ?
-- Executed: 100 times (threshold: 5)
--
-- Total patterns with warnings: 1
After Fixing with Eager Loading
-- Fixed version:
result := db.eager_loader
.from_table ("documents")
.include ("folder", "folders", "folder_id", "id")
.execute
across result.main_rows as doc loop
folder := result.first_related_for ("folder", doc.integer_64_value ("id"))
end
-- Query monitor output:
-- No N+1 patterns detected. 2 queries total.
Adjusting Threshold
if attached db.query_monitor as mon then
-- Default threshold is 5
-- Increase for batch operations that legitimately repeat
mon.set_threshold (20)
-- Or decrease for stricter checking
mon.set_threshold (3)
end
Pattern Normalization
The monitor normalizes queries to detect patterns. SELECT * FROM users WHERE id = 1 and SELECT * FROM users WHERE id = 2 are recognized as the same pattern.
Resetting Between Operations
-- Monitor multiple operations separately
if attached db.query_monitor as mon then
-- First operation
operation_a
print ("Operation A: " + mon.query_count.out + " queries%N")
-- Reset for second operation
mon.reset
-- Second operation
operation_b
print ("Operation B: " + mon.query_count.out + " queries%N")
end