fix(rules): helpful rule descriptions and threshold labels; spec alert names #6

Merged
KofTwentyTwo merged 1 commits from fix/rule-seed-text into develop 2026-10-15 17:19:00 +00:00
2 changed files with 18 additions and 18 deletions

No files matched your search

+4 -4
View File
@@ -230,11 +230,11 @@ batches, so a rerun after a crash never double counts. Each pass also writes its
`db_perf_snapshot` row (status, duration, error), which is the report even where the host runs
scheduled processes inline.
**Alerts** (core `QAlerts`; delivered by qbit-alerts when installed, logged otherwise; keyed, and
resolved when clear): `db_perf.collection_failed`, `db_perf.query_spike` (a statement's total time
**Alerts** (core `QAlerts`, type names use `dbperf.` because core rejects underscores in alert type names; delivered by qbit-alerts when installed, logged otherwise; keyed, and
resolved when clear): `dbperf.collection_failed`, `dbperf.query_spike` (a statement's total time
in an interval above `spike_factor` × its 7-day interval median and above a floor),
`db_perf.connection_saturation` (connections ≥ `connection_alert_percent` of `max_connections`),
`db_perf.blocked_chain` (a session blocked longer than `blocked_alert_seconds`).
`dbperf.connection_saturation` (connections ≥ `connection_alert_percent` of `max_connections`),
`dbperf.blocked_chain` (a session blocked longer than `blocked_alert_seconds`).
**Health** (core health SPI, Admin → Health): `db_performance.collector` (last successful snapshot
age vs interval), `db_performance.stats_access` (pg_stat_statements present, `pg_read_all_stats`
@@ -578,30 +578,30 @@ ALTER TABLE db_perf_explain ADD CONSTRAINT fk_explain_statement_id FOREIGN KEY (
-- changeset qbit-db-performance:33
-- comment: Suggestion Rules insert-only defaults; administrator edits survive.
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'SLOW_QUERY', 'Slow query', 'Slow query.', TRUE, 'WARNING', 500, 'Mean execution time (ms)', 5, 'Database time (%)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'SLOW_QUERY');
SELECT 'SLOW_QUERY', 'Slow query', 'Statements whose average run time is high, or that use a large share of all database time over the last 24 hours. Open the query and run Query plan to see why.', TRUE, 'WARNING', 500, 'Average run time (ms)', 5, 'Share of all database time (%)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'SLOW_QUERY');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'MISSING_INDEX', 'Possible missing index', 'Possible missing index.', TRUE, 'WARNING', 50, 'Sequential scan share (%)', 1000000, 'Tuples read per "day"' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'MISSING_INDEX');
SELECT 'MISSING_INDEX', 'Possible missing index', 'Tables that are mostly read by full sequential scans of many rows, where the busiest queries filter on columns no index starts with. The finding includes a CREATE INDEX CONCURRENTLY changeset to review and commit.', TRUE, 'WARNING', 50, 'Share of scans that are sequential (%)', 1000000, 'Rows read by sequential scans per day' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'MISSING_INDEX');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'UNUSED_INDEX', 'Unused index', 'Unused index.', TRUE, 'WARNING', 14, 'Days since statistics reset', 1, 'Index size (MB)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'UNUSED_INDEX');
SELECT 'UNUSED_INDEX', 'Unused index', 'Non-unique indexes that no query has used since statistics were last reset. Every write still pays to maintain them. The finding includes a DROP INDEX CONCURRENTLY changeset with a rollback.', TRUE, 'WARNING', 14, 'Days of statistics before judging', 1, 'Smallest index size to report (MB)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'UNUSED_INDEX');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'DUPLICATE_INDEX', 'Duplicate index', 'Duplicate index.', TRUE, 'WARNING', NULL, NULL, NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'DUPLICATE_INDEX');
SELECT 'DUPLICATE_INDEX', 'Duplicate index', 'Indexes with the same columns as another index on the table, or whose columns are a leading prefix of another non-unique index. Unique and primary key indexes are never proposed for removal.', TRUE, 'WARNING', NULL, NULL, NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'DUPLICATE_INDEX');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'N_PLUS_ONE', 'Repeated statements', 'Repeated statements.', TRUE, 'WARNING', 10, 'Repeats per unit', 5, 'Affected units' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'N_PLUS_ONE');
SELECT 'N_PLUS_ONE', 'Repeated statements (N+1)', 'The same statement shape run many times within one request, process or scheduled job, usually a lookup inside a loop. Batch it into one query with IN (...) or a join.', TRUE, 'WARNING', 10, 'Repeats in one unit of work', 5, 'Units of work affected per day' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'N_PLUS_ONE');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'HOT_JOB', 'Expensive job', 'Expensive job.', TRUE, 'WARNING', 10, 'Database time (%)', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'HOT_JOB');
SELECT 'HOT_JOB', 'Expensive job or process', 'Scheduled jobs and processes that account for a large share of the database time QQQ issued in the last 24 hours.', TRUE, 'WARNING', 10, 'Share of attributed database time (%)', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'HOT_JOB');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'OVER_AUDITED', 'High audit volume', 'High audit volume.', TRUE, 'WARNING', 50000, 'Audit inserts per "day"', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'OVER_AUDITED');
SELECT 'OVER_AUDITED', 'High audit volume', 'QQQ audit tables that grow by many rows a day. Lowering the audit level of the noisiest tables reduces writes and storage.', TRUE, 'WARNING', 50000, 'Audit rows inserted per day', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'OVER_AUDITED');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'BLOAT', 'Dead tuples', 'Dead tuples.', TRUE, 'WARNING', 20, 'Dead tuple ratio (%)', 10000, 'Dead tuples' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'BLOAT');
SELECT 'BLOAT', 'Dead rows (bloat)', 'Tables where a large share of rows are dead versions waiting for vacuum. Bloat slows scans and wastes space. Tune autovacuum for the table.', TRUE, 'WARNING', 20, 'Dead rows as a share of live rows (%)', 10000, 'Fewest dead rows to report' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'BLOAT');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'VACUUM_STALE', 'Stale vacuum', 'Stale vacuum.', TRUE, 'WARNING', 7, 'Days since vacuum', 150000000, 'Transaction freeze age' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'VACUUM_STALE');
SELECT 'VACUUM_STALE', 'Vacuum overdue', 'Tables with recent writes that have not been vacuumed for a long time, or whose oldest transaction ID is getting close to the freeze limit.', TRUE, 'WARNING', 7, 'Days since the last vacuum', 150000000, 'Transaction ID age (freeze age)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'VACUUM_STALE');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'POOL_SIZING', 'Connection pool sizing', 'Connection pool sizing.', TRUE, 'WARNING', 80, 'Connections used (%)', 50, 'Idle connections (%)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'POOL_SIZING');
SELECT 'POOL_SIZING', 'Connection pool sizing', 'Peak connections close to max_connections, or many idle connections held by an application. The finding suggests pool sizes per application.', TRUE, 'WARNING', 80, 'Peak connections as a share of max_connections (%)', 50, 'Idle connections as a share of all connections (%)' WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'POOL_SIZING');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'IDLE_IN_TRANSACTION', 'Idle transaction', 'Idle transaction.', TRUE, 'WARNING', 60, 'Idle seconds', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'IDLE_IN_TRANSACTION');
SELECT 'IDLE_IN_TRANSACTION', 'Idle in transaction', 'Sessions that opened a transaction and then sat idle, holding locks and blocking vacuum. Fix the transaction scope in the application.', TRUE, 'WARNING', 60, 'Seconds idle in a transaction', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'IDLE_IN_TRANSACTION');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'CACHE_HIT_LOW', 'Low cache hit ratio', 'Low cache hit ratio.', TRUE, 'WARNING', 95, 'Cache hit ratio (%)', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'CACHE_HIT_LOW');
SELECT 'CACHE_HIT_LOW', 'Low cache hit ratio', 'The share of block reads served from shared buffers fell below the threshold over the last 24 hours, so more reads go to disk.', TRUE, 'WARNING', 95, 'Cache hit ratio (%)', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'CACHE_HIT_LOW');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'TEMP_SPILL', 'Temporary disk spill', 'Temporary disk spill.', TRUE, 'WARNING', 100, 'Temporary data per "day" (MB)', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'TEMP_SPILL');
SELECT 'TEMP_SPILL', 'Temporary disk spill', 'Statements that write temporary files because sorts or hashes do not fit in work_mem.', TRUE, 'WARNING', 100, 'Temporary data written per day (MB)', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'TEMP_SPILL');
INSERT INTO db_perf_rule (code,label,description,enabled,severity,threshold_1,threshold_1_label,threshold_2,threshold_2_label)
SELECT 'DEADLOCKS', 'Deadlocks', 'Deadlocks.', TRUE, 'WARNING', 1, 'Deadlocks per "day"', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'DEADLOCKS');
SELECT 'DEADLOCKS', 'Deadlocks', 'Transactions that deadlocked and were cancelled by PostgreSQL. Usually two code paths that lock rows in a different order.', TRUE, 'WARNING', 1, 'Deadlocks per day', NULL, NULL WHERE NOT EXISTS (SELECT 1 FROM db_perf_rule WHERE code = 'DEADLOCKS');