BigAl can add SQL comments to the queries it runs. Monitoring tools show the comment with the query text, so you can tell which route, job, or call site sent a slow query.
sql
SELECT /* route=GET /stores/:id */ /* listStoreProducts */ "id","name","sku","store_id" AS "store" FROM "products" WHERE "store_id"=$1
There are two ways to tag queries, and you can use both:
Tag one query with .comment() on a read or the comment option on a write.
Tag every query from a request or job with the queryComment option on initialize().
.comment() can appear anywhere in the chain. If you call it twice, BigAl keeps the second text.
Pass the comment through .comment(), not inside the find() arguments. BigAl treats unknown keys in those arguments as where criteria, so find({ comment: 'loadProduct' }) filters on a comment column.
Populate queries inherit the comment from their find() or findOne():
ts
const store = await storeRepository.findOne().where({ id: storeId }).populate('products').comment('loadStoreWithProducts');
Both queries carry the tag:
sql
SELECT /* loadStoreWithProducts */ "id","name" FROM "stores" WHERE "id"=$1 LIMIT 1SELECT /* loadStoreWithProducts */ "id","name","sku","store_id" AS "store" FROM "products" WHERE "store_id"=$1
A many-to-many populate tags both the junction-table query and the related-table query.
INSERT /* createProduct */ INTO "products" ("name","store_id") VALUES ($1,$2) RETURNING "id","name","sku","store_id" AS "store"UPDATE /* renameSkus */ "products" SET "sku"=$1 WHERE "id"=ANY($2::INTEGER[])DELETE /* removeObsoleteProducts */ FROM "products" WHERE "id"=ANY($1::INTEGER[])
Every repository query inside the callback receives the tag. This includes populate queries and queries in a managed transaction(). If a query also has its own comment, the queryComment text comes first:
sql
SELECT /* route=GET /stores/:id */ /* loadStoreWithProducts */ "id","name" FROM "stores" WHERE "id"=$1 LIMIT 1
Use route patterns such as /stores/:id, not raw URLs such as /stores/42. A raw URL creates a new tag for every ID and can copy user data into your monitoring tools.
pg_stat_statements keeps running totals for each query shape:
sql
SELECT calls, round(total_exec_time) AS total_ms, round(mean_exec_time::numeric, 1) AS mean_ms, queryFROM pg_stat_statementsWHERE query LIKE '%/* listStoreProducts */%'ORDER BY total_exec_time DESC;
pg_stat_statements ignores comments when it groups queries. If two tags run the same SQL, they share one row, and the query column shows the text that ran first.
pg_stat_activity shows queries that are running now, with their full text:
sql
SELECT pid, now() - query_start AS duration, queryFROM pg_stat_activityWHERE state = 'active' AND query LIKE '%route=GET /stores/:id%' AND pid <> pg_backend_pid();
The Top SQL tab in Performance Insights shows the first 500 bytes of each statement by default. BigAl puts its comments after the first keyword, inside that window.
Placement: Comments go immediately after the first keyword. PostgreSQL 18 drops comments that come before the first keyword from pg_stat_statements. pg_stat_activity cuts query text off at track_activity_query_size, which is 1024 bytes by default. That can hide a comment at the end of a long query.
Allowed text: A comment cannot contain /* or */. PostgreSQL nests block comments, so either sequence could change the SQL that runs. BigAl throws instead of running the query. It also throws when the comment is not a string.
Order: When a query has both types of comment, the queryComment text comes first.
Not tagged: Raw queries that you run on a pool, TransactionScope.query(), and transaction statements such as BEGIN and COMMIT.
Query Comments
BigAl can add SQL comments to the queries it runs. Monitoring tools show the comment with the query text, so you can tell which route, job, or call site sent a slow query.
There are two ways to tag queries, and you can use both:
.comment()on a read or thecommentoption on a write.queryCommentoption oninitialize().Tag one query
Reads
find(),findOne(), andcount()accept.comment():.comment()can appear anywhere in the chain. If you call it twice, BigAl keeps the second text.Pass the comment through
.comment(), not inside thefind()arguments. BigAl treats unknown keys in those arguments as where criteria, sofind({ comment: 'loadProduct' })filters on acommentcolumn.Populate queries
Populate queries inherit the comment from their
find()orfindOne():Both queries carry the tag:
A many-to-many populate tags both the junction-table query and the related-table query.
Writes
create(),update(), anddestroy()accept acommentoption:Tag every query from a request or job
BigAl calls
queryCommentbefore each repository query. The function returns the text to add orundefinedto leave the query untagged.Store the tag in
AsyncLocalStorage, so each request or job carries its own:Wrap each request handler and job in
withQueryTag():Every repository query inside the callback receives the tag. This includes populate queries and queries in a managed
transaction(). If a query also has its own comment, thequeryCommenttext comes first:Use route patterns such as
/stores/:id, not raw URLs such as/stores/42. A raw URL creates a new tag for every ID and can copy user data into your monitoring tools.Find tagged queries
pg_stat_statements
pg_stat_statementskeeps running totals for each query shape:pg_stat_statementsignores comments when it groups queries. If two tags run the same SQL, they share one row, and thequerycolumn shows the text that ran first.pg_stat_activity
pg_stat_activityshows queries that are running now, with their full text:AWS Performance Insights
The Top SQL tab in Performance Insights shows the first 500 bytes of each statement by default. BigAl puts its comments after the first keyword, inside that window.
Rules and limits
pg_stat_statements.pg_stat_activitycuts query text off attrack_activity_query_size, which is 1024 bytes by default. That can hide a comment at the end of a long query./*or*/. PostgreSQL nests block comments, so either sequence could change the SQL that runs. BigAl throws instead of running the query. It also throws when the comment is not a string.queryCommenttext comes first.TransactionScope.query(), and transaction statements such asBEGINandCOMMIT.