pg_reports 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +12 -4
- data/app/views/layouts/pg_reports/application.html.erb +70 -61
- data/app/views/pg_reports/dashboard/_show_scripts.html.erb +53 -1
- data/app/views/pg_reports/dashboard/_show_styles.html.erb +31 -11
- data/app/views/pg_reports/dashboard/index.html.erb +14 -8
- data/app/views/pg_reports/dashboard/show.html.erb +6 -2
- data/config/locales/en.yml +109 -0
- data/config/locales/ru.yml +81 -0
- data/config/locales/uk.yml +126 -0
- data/lib/pg_reports/compatibility.rb +63 -0
- data/lib/pg_reports/configuration.rb +2 -0
- data/lib/pg_reports/dashboard/reports_registry.rb +36 -0
- data/lib/pg_reports/definitions/indexes/fk_without_indexes.yml +30 -0
- data/lib/pg_reports/definitions/indexes/index_correlation.yml +31 -0
- data/lib/pg_reports/definitions/indexes/inefficient_indexes.yml +45 -0
- data/lib/pg_reports/definitions/queries/temp_file_queries.yml +39 -0
- data/lib/pg_reports/definitions/system/wraparound_risk.yml +31 -0
- data/lib/pg_reports/definitions/tables/tables_without_pk.yml +28 -0
- data/lib/pg_reports/engine.rb +6 -0
- data/lib/pg_reports/modules/indexes.rb +3 -0
- data/lib/pg_reports/modules/queries.rb +1 -0
- data/lib/pg_reports/modules/system.rb +27 -0
- data/lib/pg_reports/modules/tables.rb +1 -0
- data/lib/pg_reports/query_monitor.rb +64 -32
- data/lib/pg_reports/sql/indexes/fk_without_indexes.sql +23 -0
- data/lib/pg_reports/sql/indexes/index_correlation.sql +27 -0
- data/lib/pg_reports/sql/indexes/inefficient_indexes.sql +22 -0
- data/lib/pg_reports/sql/queries/temp_file_queries.sql +16 -0
- data/lib/pg_reports/sql/system/checkpoint_stats.sql +20 -0
- data/lib/pg_reports/sql/system/checkpoint_stats_legacy.sql +19 -0
- data/lib/pg_reports/sql/system/wraparound_risk.sql +21 -0
- data/lib/pg_reports/sql/tables/tables_without_pk.sql +20 -0
- data/lib/pg_reports/version.rb +1 -1
- data/lib/pg_reports.rb +5 -0
- metadata +16 -1
data/config/locales/en.yml
CHANGED
|
@@ -11,6 +11,7 @@ en:
|
|
|
11
11
|
- "High mean time can be caused by: missing index, suboptimal plan, locks, disk I/O load."
|
|
12
12
|
- "For composite indexes, column order matters — index (a, b) is effective for WHERE a = ? and WHERE a = ? AND b = ?, but not for WHERE b = ?."
|
|
13
13
|
- "Queries with LIKE '%pattern%' cannot use B-tree indexes — consider pg_trgm or full-text search."
|
|
14
|
+
ai_prompt: "Optimize these slow PostgreSQL queries. For each query: analyze the query plan, identify missing indexes, suggest query rewrites. If an index is needed, generate a Rails migration. If the query can be rewritten, show the optimized version."
|
|
14
15
|
|
|
15
16
|
heavy_queries:
|
|
16
17
|
title: "Heavy Queries"
|
|
@@ -21,6 +22,7 @@ en:
|
|
|
21
22
|
- "N+1 problem: if you see many similar queries with different IDs — this is a sign of N+1, need eager loading."
|
|
22
23
|
- "Consider batch operations instead of multiple single queries."
|
|
23
24
|
- "Prepared statements can reduce parsing overhead for frequent queries."
|
|
25
|
+
ai_prompt: "Reduce the call frequency of these heavy PostgreSQL queries. For each query: identify the caller in application code, suggest caching strategies (Redis/Memcached), detect N+1 patterns and suggest eager loading fixes. Show code changes needed."
|
|
24
26
|
|
|
25
27
|
expensive_queries:
|
|
26
28
|
title: "Expensive Queries"
|
|
@@ -30,6 +32,7 @@ en:
|
|
|
30
32
|
- "A query can be fast but called so often that it takes a lot of time in total."
|
|
31
33
|
- "Optimizing expensive queries has the greatest effect on overall system performance."
|
|
32
34
|
- "Consider: adding indexes, rewriting the query, caching results, materialized views."
|
|
35
|
+
ai_prompt: "Optimize these expensive PostgreSQL queries that consume the most total database time. For each query: analyze the execution plan, suggest indexes or query rewrites, estimate the expected improvement. Generate Rails migrations for any new indexes."
|
|
33
36
|
|
|
34
37
|
missing_index_queries:
|
|
35
38
|
title: "Missing Index Queries"
|
|
@@ -40,6 +43,7 @@ en:
|
|
|
40
43
|
- "Composite index (a, b, c) covers: WHERE a, WHERE a AND b, WHERE a AND b AND c, but does NOT cover WHERE b or WHERE c."
|
|
41
44
|
- "EXPLAIN ANALYZE will show the actual query execution plan."
|
|
42
45
|
- "Partial indexes (CREATE INDEX ... WHERE condition) save space and speed up specific queries."
|
|
46
|
+
ai_prompt: "Add missing indexes for these PostgreSQL queries that perform sequential scans. For each table: analyze the query pattern, determine optimal index columns, generate a Rails migration with add_index. Consider partial indexes where appropriate."
|
|
43
47
|
|
|
44
48
|
low_cache_hit_queries:
|
|
45
49
|
title: "Low Cache Hit Queries"
|
|
@@ -50,6 +54,18 @@ en:
|
|
|
50
54
|
- "Low cache hit may indicate: insufficient shared_buffers, tables too large, inefficient queries scanning too much data."
|
|
51
55
|
- "Increasing shared_buffers helps, but there's a limit to effectiveness (typically 25% of RAM)."
|
|
52
56
|
- "Covering indexes (INCLUDE) allow index-only scans without accessing the table."
|
|
57
|
+
ai_prompt: "Improve cache hit ratio for these PostgreSQL queries. For each query: suggest covering indexes (with INCLUDE columns) to enable index-only scans, or suggest query rewrites to reduce the data scanned. Generate Rails migrations for new indexes."
|
|
58
|
+
|
|
59
|
+
temp_file_queries:
|
|
60
|
+
title: "Temp File Queries"
|
|
61
|
+
what: "Queries that spill intermediate results to temporary files on disk."
|
|
62
|
+
how: "Analyzes temp_blks_written and temp_blks_read from pg_stat_statements. Temporary files are created when work_mem is insufficient for sorting, hashing, or materializing."
|
|
63
|
+
nuances:
|
|
64
|
+
- "Temp file writes are orders of magnitude slower than in-memory operations."
|
|
65
|
+
- "Increasing work_mem can eliminate temp files, but affects all sessions — use SET LOCAL for specific queries."
|
|
66
|
+
- "Common causes: large sorts (ORDER BY), hash joins on big tables, DISTINCT on many rows, complex CTEs."
|
|
67
|
+
- "Consider adding indexes to avoid sorts, or rewriting queries to reduce intermediate result sets."
|
|
68
|
+
ai_prompt: "Fix these PostgreSQL queries that spill to temporary files on disk. For each query: identify the cause (large sort, hash join, DISTINCT), suggest an index to avoid the sort, or suggest SET LOCAL work_mem for specific code paths. Show the code changes."
|
|
53
69
|
|
|
54
70
|
all_queries:
|
|
55
71
|
title: "All Queries"
|
|
@@ -70,6 +86,7 @@ en:
|
|
|
70
86
|
- "Indexes are still updated on INSERT/UPDATE/DELETE, even if not used for reading — this is overhead."
|
|
71
87
|
- "Unique indexes (UNIQUE) may have 0 scans but are needed for constraints."
|
|
72
88
|
- "Foreign key indexes are important for DELETE/UPDATE performance on parent tables."
|
|
89
|
+
ai_prompt: "Remove these unused PostgreSQL indexes. For each index: generate a Rails migration with remove_index. Group related indexes into one migration. Add a safety comment noting the index can be recreated if needed."
|
|
73
90
|
|
|
74
91
|
duplicate_indexes:
|
|
75
92
|
title: "Duplicate Indexes"
|
|
@@ -79,6 +96,7 @@ en:
|
|
|
79
96
|
- "Duplicates waste disk space and slow down INSERT/UPDATE/DELETE."
|
|
80
97
|
- "However, sometimes a 'duplicate' is needed: different index types (B-tree vs GIN), partial vs full index."
|
|
81
98
|
- "Index (a, b) does NOT fully replace (b, a) — column order is critical."
|
|
99
|
+
ai_prompt: "Remove these duplicate PostgreSQL indexes. For each pair: determine which index is redundant (the shorter prefix), generate a Rails migration with remove_index for the redundant one. Verify the remaining index covers all use cases."
|
|
82
100
|
|
|
83
101
|
invalid_indexes:
|
|
84
102
|
title: "Invalid Indexes"
|
|
@@ -88,6 +106,7 @@ en:
|
|
|
88
106
|
- "Usually appear after a failed CREATE INDEX CONCURRENTLY."
|
|
89
107
|
- "Solution: DROP INDEX and recreate."
|
|
90
108
|
- "REINDEX CONCURRENTLY can help for existing invalid indexes (PostgreSQL 12+)."
|
|
109
|
+
ai_prompt: "Fix these invalid PostgreSQL indexes. For each index: generate a Rails migration that drops the invalid index and recreates it using `algorithm: :concurrently` to avoid locking the table."
|
|
91
110
|
|
|
92
111
|
missing_indexes:
|
|
93
112
|
title: "Missing Indexes"
|
|
@@ -97,6 +116,7 @@ en:
|
|
|
97
116
|
- "Not all seq_scans are bad — for small tables it's optimal."
|
|
98
117
|
- "Analyze specific queries via pg_stat_statements to understand which columns to index."
|
|
99
118
|
- "Use EXPLAIN ANALYZE to verify if an index will be used."
|
|
119
|
+
ai_prompt: "Add missing indexes for these PostgreSQL tables with high sequential scan counts. For each table: analyze the common query patterns, determine optimal index columns, generate a Rails migration with add_index using `algorithm: :concurrently`."
|
|
100
120
|
|
|
101
121
|
index_usage:
|
|
102
122
|
title: "Index Usage"
|
|
@@ -107,6 +127,18 @@ en:
|
|
|
107
127
|
- "idx_tup_read — rows read from the index."
|
|
108
128
|
- "idx_tup_fetch — rows fetched from table after index scan (for non-covering indexes)."
|
|
109
129
|
|
|
130
|
+
inefficient_indexes:
|
|
131
|
+
title: "Inefficient Indexes"
|
|
132
|
+
what: "Indexes that are used but scan far more entries than they actually fetch."
|
|
133
|
+
how: "Compares idx_tup_read (index entries scanned) vs idx_tup_fetch (heap rows fetched) from pg_stat_user_indexes. A high ratio means the index column order doesn't match query predicates, forcing PostgreSQL to scan large index ranges."
|
|
134
|
+
nuances:
|
|
135
|
+
- "A read-to-fetch ratio >10 means the index reads 10x more entries than it returns — strong sign of misaligned column order."
|
|
136
|
+
- "For composite indexes (a, b, c), queries filtering on (b) or (c) without (a) cannot seek directly and must scan wider ranges."
|
|
137
|
+
- "Solution: create a targeted index with columns matching the most selective WHERE predicates first."
|
|
138
|
+
- "Use EXPLAIN ANALYZE to confirm the index scan is reading excessive entries before making changes."
|
|
139
|
+
- "Index-only scans (where idx_tup_fetch = 0) are excluded — they indicate covering indexes working efficiently."
|
|
140
|
+
ai_prompt: "Fix these inefficient PostgreSQL index scans. For each index: analyze the index definition and identify the misaligned column order, create a new targeted index with columns matching the most selective WHERE predicates first, generate a Rails migration that adds the new index and removes the old one."
|
|
141
|
+
|
|
110
142
|
bloated_indexes:
|
|
111
143
|
title: "Bloated Indexes"
|
|
112
144
|
what: "Indexes with high bloat level due to dead tuples."
|
|
@@ -116,6 +148,30 @@ en:
|
|
|
116
148
|
- "Regular VACUUM keeps bloat at acceptable levels."
|
|
117
149
|
- "pg_repack allows rebuilding indexes without locks."
|
|
118
150
|
- "Bloat >30-50% — reason for action."
|
|
151
|
+
ai_prompt: "Rebuild these bloated PostgreSQL indexes. Generate a rake task or Rails migration that runs REINDEX CONCURRENTLY for each bloated index to reclaim disk space without locking the table."
|
|
152
|
+
|
|
153
|
+
fk_without_indexes:
|
|
154
|
+
title: "FK Without Indexes"
|
|
155
|
+
what: "Foreign keys on child tables that lack a supporting index."
|
|
156
|
+
how: "Compares pg_constraint (foreign keys) with pg_index to find FK columns without a matching leading index column."
|
|
157
|
+
nuances:
|
|
158
|
+
- "Without an index, DELETE or UPDATE on the parent table triggers a sequential scan on the child table."
|
|
159
|
+
- "On large child tables this can cause severe lock contention and slow cascading operations."
|
|
160
|
+
- "The index must have the FK column as the leading (first) column to be effective."
|
|
161
|
+
- "Small tables (< 10K rows) may not benefit from adding an index — PostgreSQL will prefer seq scan anyway."
|
|
162
|
+
ai_prompt: "Add missing indexes on foreign key columns in these PostgreSQL tables. For each FK: generate a Rails migration with add_index on the child table's FK column. Use `algorithm: :concurrently` for large tables."
|
|
163
|
+
|
|
164
|
+
index_correlation:
|
|
165
|
+
title: "Index Correlation"
|
|
166
|
+
what: "Indexes where physical row order poorly matches the index order."
|
|
167
|
+
how: "Reads pg_stats.correlation for leading index columns. Correlation near 0 means random physical order relative to the index, causing excessive random I/O on range scans."
|
|
168
|
+
nuances:
|
|
169
|
+
- "Correlation ranges from -1 to 1. Values near 0 mean random order; near 1 or -1 mean ordered."
|
|
170
|
+
- "Low correlation mainly impacts range scans (BETWEEN, >, <) and ORDER BY — point lookups are less affected."
|
|
171
|
+
- "CLUSTER table USING index physically reorders rows but locks the table and is not maintained automatically."
|
|
172
|
+
- "For append-only tables with timestamp columns, correlation is naturally high — no action needed."
|
|
173
|
+
- "Only tables > 10MB with > 100 index scans are shown to reduce noise."
|
|
174
|
+
ai_prompt: "Address low physical correlation for these PostgreSQL indexes. For each: evaluate if CLUSTER is appropriate (for read-heavy tables), or suggest switching to BRIN index for range-scanned timestamp columns. If CLUSTER is chosen, generate a rake task since it locks the table and should be run during maintenance."
|
|
119
175
|
|
|
120
176
|
index_sizes:
|
|
121
177
|
title: "Index Sizes"
|
|
@@ -145,6 +201,7 @@ en:
|
|
|
145
201
|
- "VACUUM FULL physically reduces file size, but locks the table."
|
|
146
202
|
- "autovacuum should handle this automatically — check its settings if you see high bloat."
|
|
147
203
|
- "Dead tuple ratio >20% — signal of vacuum problems."
|
|
204
|
+
ai_prompt: "Fix bloat on these PostgreSQL tables with high dead tuple percentage. Generate a rake task that runs VACUUM ANALYZE on each table. For severely bloated tables, suggest VACUUM FULL during maintenance window. Also review autovacuum settings."
|
|
148
205
|
|
|
149
206
|
vacuum_needed:
|
|
150
207
|
title: "Vacuum Needed"
|
|
@@ -154,6 +211,7 @@ en:
|
|
|
154
211
|
- "last_vacuum and last_autovacuum show when vacuum last ran."
|
|
155
212
|
- "If autovacuum can't keep up, you can: lower autovacuum_vacuum_threshold, increase autovacuum_vacuum_scale_factor, add workers."
|
|
156
213
|
- "For critical tables, you can set individual parameters: ALTER TABLE SET (autovacuum_vacuum_threshold = 1000)."
|
|
214
|
+
ai_prompt: "Fix vacuum issues on these PostgreSQL tables. Generate a rake task that runs VACUUM ANALYZE on each table. For tables with extreme dead rows, suggest tuning per-table autovacuum parameters via a Rails migration using execute."
|
|
157
215
|
|
|
158
216
|
row_counts:
|
|
159
217
|
title: "Row Counts"
|
|
@@ -172,6 +230,7 @@ en:
|
|
|
172
230
|
- "Target value: >95% for actively used tables."
|
|
173
231
|
- "Low cache hit: table too large for cache or rarely used."
|
|
174
232
|
- "Solutions: increase shared_buffers, optimize queries, add indexes to reduce scanned data."
|
|
233
|
+
ai_prompt: "Improve cache hit ratios for these PostgreSQL tables. Suggest specific shared_buffers tuning, recommend indexes to reduce data scanned, and identify queries hitting these tables that could benefit from optimization."
|
|
175
234
|
|
|
176
235
|
seq_scans:
|
|
177
236
|
title: "Sequential Scans"
|
|
@@ -182,6 +241,18 @@ en:
|
|
|
182
241
|
- "seq_tup_read shows how many rows were read — this is more important than scan count."
|
|
183
242
|
- "High seq_tup_read/seq_scan = many rows per scan = probably normal."
|
|
184
243
|
- "Low seq_tup_read/seq_scan = many small scans = possibly N+1."
|
|
244
|
+
ai_prompt: "Add indexes for these PostgreSQL tables with high sequential scan counts. For each table: identify the queries causing sequential scans, determine optimal index columns, generate a Rails migration with add_index."
|
|
245
|
+
|
|
246
|
+
tables_without_pk:
|
|
247
|
+
title: "Tables Without Primary Keys"
|
|
248
|
+
what: "Tables that have no primary key defined."
|
|
249
|
+
how: "Checks pg_index for missing indisprimary entries on user tables."
|
|
250
|
+
nuances:
|
|
251
|
+
- "Logical replication requires a primary key or REPLICA IDENTITY to identify rows."
|
|
252
|
+
- "Without a PK, UPDATE and DELETE need another way to uniquely identify rows, often resulting in full table scans."
|
|
253
|
+
- "Join tables (many-to-many) often lack PKs intentionally — consider adding a composite PK."
|
|
254
|
+
- "Some ORMs (e.g., Rails) assume an 'id' primary key — tables without it may cause framework errors."
|
|
255
|
+
ai_prompt: "Add primary keys to these PostgreSQL tables. For each table: determine the appropriate primary key (auto-increment id or composite key for join tables), generate a Rails migration that adds the primary key."
|
|
185
256
|
|
|
186
257
|
recently_modified:
|
|
187
258
|
title: "Recently Modified"
|
|
@@ -220,6 +291,7 @@ en:
|
|
|
220
291
|
- "Long queries can hold locks and interfere with other processes."
|
|
221
292
|
- "statement_timeout can automatically terminate queries running too long."
|
|
222
293
|
- "For reports/analytics, use a read replica or configure a separate connection pool."
|
|
294
|
+
ai_prompt: "Investigate and optimize these long-running PostgreSQL queries. For each query: analyze the execution plan, suggest indexes or query rewrites, recommend statement_timeout configuration. If the query is analytical, suggest moving it to a read replica."
|
|
223
295
|
|
|
224
296
|
blocking_queries:
|
|
225
297
|
title: "Blocking Queries"
|
|
@@ -230,6 +302,7 @@ en:
|
|
|
230
302
|
- "Common causes: long transactions, missing indexes on UPDATE/DELETE with FK."
|
|
231
303
|
- "pg_cancel_backend(pid) cancels query, pg_terminate_backend(pid) terminates connection."
|
|
232
304
|
- "Consider optimistic locking at the application level."
|
|
305
|
+
ai_prompt: "Resolve these blocking query chains in PostgreSQL. Identify the root blocker, suggest application-level fixes (shorter transactions, optimistic locking, advisory locks), and recommend indexes on FK columns to speed up cascading operations."
|
|
233
306
|
|
|
234
307
|
locks:
|
|
235
308
|
title: "Locks"
|
|
@@ -248,6 +321,7 @@ en:
|
|
|
248
321
|
- "A moderate number of idle connections is normal for connection pooling."
|
|
249
322
|
- "Too many idle = application not closing connections or pool is too large."
|
|
250
323
|
- "idle_session_timeout (PostgreSQL 14+) can automatically close idle connections."
|
|
324
|
+
ai_prompt: "Reduce idle PostgreSQL connections. Suggest database.yml pool size tuning, recommend idle_session_timeout or PgBouncer configuration, and identify application code that may be leaking connections."
|
|
251
325
|
|
|
252
326
|
pool_usage:
|
|
253
327
|
title: "Connection Pool Usage"
|
|
@@ -278,6 +352,7 @@ en:
|
|
|
278
352
|
- "High idle in transaction count = application transaction handling issues."
|
|
279
353
|
- "superuser_reserved_connections reduce available pool capacity."
|
|
280
354
|
- "Monitor trends — sudden spikes may indicate connection leaks."
|
|
355
|
+
ai_prompt: "Fix connection pool saturation in PostgreSQL. Suggest specific max_connections and pool size tuning for database.yml, recommend PgBouncer setup if not present, and identify application patterns causing pool exhaustion."
|
|
281
356
|
|
|
282
357
|
connection_churn:
|
|
283
358
|
title: "Connection Churn Analysis"
|
|
@@ -288,6 +363,7 @@ en:
|
|
|
288
363
|
- "Churn rate over 50% = missing/misconfigured connection pooling."
|
|
289
364
|
- "Many short connections = increased CPU and authentication overhead."
|
|
290
365
|
- "Web apps should maintain connection pools, not create per-request connections."
|
|
366
|
+
ai_prompt: "Fix excessive connection churn in PostgreSQL. Configure PgBouncer or Rails connection pooling properly, identify application code creating short-lived connections, suggest database.yml pool and checkout_timeout tuning."
|
|
291
367
|
|
|
292
368
|
# === SYSTEM ===
|
|
293
369
|
database_sizes:
|
|
@@ -326,6 +402,30 @@ en:
|
|
|
326
402
|
- "Useful for quick assessment of database state."
|
|
327
403
|
- "Compare with baseline to identify anomalies."
|
|
328
404
|
|
|
405
|
+
wraparound_risk:
|
|
406
|
+
title: "Wraparound Risk"
|
|
407
|
+
what: "Transaction ID age proximity to the 2-billion wraparound limit."
|
|
408
|
+
how: "Reads age(datfrozenxid) from pg_database. When this approaches 2^31 (~2.1 billion), PostgreSQL will shut down to prevent data corruption."
|
|
409
|
+
nuances:
|
|
410
|
+
- "autovacuum_freeze_max_age (default 200M) triggers aggressive anti-wraparound VACUUM automatically."
|
|
411
|
+
- "If age exceeds freeze_max_age, anti-wraparound VACUUM should already be running — if not, investigate why."
|
|
412
|
+
- "Long-running transactions prevent VACUUM from advancing the frozen XID — monitor idle-in-transaction."
|
|
413
|
+
- "In emergencies, run VACUUM FREEZE on the largest/oldest tables first."
|
|
414
|
+
- "Pct > 50% is a warning; > 75% is critical and requires immediate action."
|
|
415
|
+
ai_prompt: "Address transaction ID wraparound risk on these PostgreSQL databases. Generate a rake task that runs VACUUM FREEZE on the affected databases, prioritizing by pct_towards_wraparound. Include monitoring checks to verify the XID age decreased after the operation."
|
|
416
|
+
|
|
417
|
+
checkpoint_stats:
|
|
418
|
+
title: "Checkpoint Stats"
|
|
419
|
+
what: "Checkpoint frequency and background writer performance metrics."
|
|
420
|
+
how: "Data from pg_stat_bgwriter shows checkpoint counts, timing, and buffer write distribution."
|
|
421
|
+
nuances:
|
|
422
|
+
- "checkpoints_timed = scheduled checkpoints (healthy); checkpoints_req = forced checkpoints (under pressure)."
|
|
423
|
+
- "High requested_pct means WAL fills up before checkpoint_timeout — increase max_wal_size."
|
|
424
|
+
- "buffers_backend > 0 means backends write dirty buffers themselves — increase shared_buffers or bgwriter activity."
|
|
425
|
+
- "bgwriter_stops (maxwritten_clean) > 0 means bgwriter hit its per-round limit — increase bgwriter_lru_maxpages."
|
|
426
|
+
- "Stats accumulate since stats_reset — compare over time for meaningful analysis."
|
|
427
|
+
ai_prompt: "Optimize PostgreSQL checkpoint and background writer configuration based on these stats. Suggest specific postgresql.conf parameter changes (max_wal_size, checkpoint_completion_target, bgwriter_lru_maxpages) with recommended values and explain the expected impact."
|
|
428
|
+
|
|
329
429
|
cache_stats:
|
|
330
430
|
title: "Cache Stats"
|
|
331
431
|
what: "Database caching statistics."
|
|
@@ -334,6 +434,7 @@ en:
|
|
|
334
434
|
- "Cache hit ratio = blks_hit / (blks_hit + blks_read)."
|
|
335
435
|
- "Target value: >99% for OLTP, >95% for mixed workload."
|
|
336
436
|
- "Low cache hit: increase shared_buffers (up to 25% RAM), or the problem is in queries."
|
|
437
|
+
ai_prompt: "Improve PostgreSQL cache hit ratio. Suggest specific shared_buffers and effective_cache_size tuning for postgresql.conf based on the current stats. Recommend application-level caching for frequently accessed data."
|
|
337
438
|
|
|
338
439
|
# === SCHEMA ANALYSIS ===
|
|
339
440
|
missing_validations:
|
|
@@ -347,6 +448,7 @@ en:
|
|
|
347
448
|
- "Some tables may not have models — this is normal for join tables or legacy tables."
|
|
348
449
|
- "Validations in concerns and parent models are also detected."
|
|
349
450
|
- "Primary keys don't need validations — they are automatically unique."
|
|
451
|
+
ai_prompt: "Add missing uniqueness validations to these Rails models. For each unique index: add `validates :column, uniqueness: true` (or with `scope:` for composite indexes) to the corresponding model. Handle STI and concern-based models correctly."
|
|
350
452
|
|
|
351
453
|
# Problem explanations for highlighting
|
|
352
454
|
problems:
|
|
@@ -356,6 +458,13 @@ en:
|
|
|
356
458
|
low_cache_hit: "Low cache hit ratio. Query frequently reads from disk instead of cache."
|
|
357
459
|
high_seq_scan: "Many sequential scans. Possibly missing an index."
|
|
358
460
|
unused_index: "Index is not used. Candidate for removal."
|
|
461
|
+
inefficient_index: "Index reads far more entries than it fetches. Composite index column order likely misaligned with query predicates."
|
|
462
|
+
fk_without_index: "Foreign key column has no supporting index. DELETE/UPDATE on parent table will cause sequential scan."
|
|
463
|
+
low_correlation: "Low physical correlation between index and row order. Range scans will cause excessive random I/O."
|
|
464
|
+
temp_file_heavy: "Query spills data to temporary files on disk. Consider increasing work_mem or optimizing the query."
|
|
465
|
+
missing_pk: "Table has no primary key. This breaks logical replication and may cause issues with ORMs."
|
|
466
|
+
wraparound_risk: "Transaction ID age is approaching the wraparound limit. VACUUM FREEZE required."
|
|
467
|
+
high_checkpoint_req: "High percentage of forced checkpoints. Consider increasing max_wal_size."
|
|
359
468
|
high_bloat: "High bloat. REINDEX or VACUUM required."
|
|
360
469
|
many_dead_tuples: "Many dead tuples. VACUUM required."
|
|
361
470
|
long_running: "Long-running query. May block other operations."
|
data/config/locales/ru.yml
CHANGED
|
@@ -51,6 +51,16 @@ ru:
|
|
|
51
51
|
- "Увеличение shared_buffers помогает, но есть предел эффективности (обычно 25% RAM)."
|
|
52
52
|
- "Covering indexes (INCLUDE) позволяют выполнять index-only scan без обращения к таблице."
|
|
53
53
|
|
|
54
|
+
temp_file_queries:
|
|
55
|
+
title: "Temp File Queries"
|
|
56
|
+
what: "Запросы, сбрасывающие промежуточные результаты во временные файлы на диск."
|
|
57
|
+
how: "Анализирует temp_blks_written и temp_blks_read из pg_stat_statements. Временные файлы создаются, когда work_mem недостаточен для сортировки, хеширования или материализации."
|
|
58
|
+
nuances:
|
|
59
|
+
- "Запись во временные файлы на порядки медленнее, чем операции в памяти."
|
|
60
|
+
- "Увеличение work_mem может устранить временные файлы, но влияет на все сессии — используйте SET LOCAL для конкретных запросов."
|
|
61
|
+
- "Частые причины: большие сортировки (ORDER BY), hash join на больших таблицах, DISTINCT на множестве строк, сложные CTE."
|
|
62
|
+
- "Рассмотрите добавление индексов для устранения сортировок или переписывание запросов для уменьшения промежуточных результатов."
|
|
63
|
+
|
|
54
64
|
all_queries:
|
|
55
65
|
title: "All Queries"
|
|
56
66
|
what: "Полная статистика по всем запросам из pg_stat_statements."
|
|
@@ -107,6 +117,17 @@ ru:
|
|
|
107
117
|
- "idx_tup_read — строки прочитанные из индекса."
|
|
108
118
|
- "idx_tup_fetch — строки извлечённые из таблицы после index scan (для non-covering indexes)."
|
|
109
119
|
|
|
120
|
+
inefficient_indexes:
|
|
121
|
+
title: "Inefficient Indexes"
|
|
122
|
+
what: "Индексы, которые используются, но сканируют гораздо больше записей, чем реально извлекают."
|
|
123
|
+
how: "Сравнивает idx_tup_read (записей прочитано из индекса) и idx_tup_fetch (строк извлечено из heap) из pg_stat_user_indexes. Высокое соотношение означает, что порядок колонок индекса не соответствует предикатам запроса, вынуждая PostgreSQL сканировать большие диапазоны индекса."
|
|
124
|
+
nuances:
|
|
125
|
+
- "Соотношение read/fetch >10 означает, что индекс читает в 10+ раз больше записей, чем возвращает — явный признак неправильного порядка колонок."
|
|
126
|
+
- "Для составных индексов (a, b, c) запросы, фильтрующие по (b) или (c) без (a), не могут выполнить точный seek и вынуждены сканировать широкие диапазоны."
|
|
127
|
+
- "Решение: создать целевой индекс с колонками, соответствующими наиболее селективным WHERE-предикатам в первую очередь."
|
|
128
|
+
- "Используйте EXPLAIN ANALYZE для подтверждения, что index scan читает избыточное количество записей, прежде чем вносить изменения."
|
|
129
|
+
- "Index-only scans (где idx_tup_fetch = 0) исключены — они указывают на эффективно работающие covering indexes."
|
|
130
|
+
|
|
110
131
|
bloated_indexes:
|
|
111
132
|
title: "Bloated Indexes"
|
|
112
133
|
what: "Индексы с высоким уровнем bloat (раздувания) из-за мёртвых кортежей."
|
|
@@ -117,6 +138,27 @@ ru:
|
|
|
117
138
|
- "pg_repack позволяет перестроить индексы без блокировок."
|
|
118
139
|
- "Bloat >30-50% — повод для действий."
|
|
119
140
|
|
|
141
|
+
fk_without_indexes:
|
|
142
|
+
title: "FK Without Indexes"
|
|
143
|
+
what: "Внешние ключи на дочерних таблицах без поддерживающего индекса."
|
|
144
|
+
how: "Сравнивает pg_constraint (внешние ключи) с pg_index для поиска FK-колонок без соответствующего ведущего индекса."
|
|
145
|
+
nuances:
|
|
146
|
+
- "Без индекса DELETE или UPDATE родительской таблицы вызывает sequential scan дочерней таблицы."
|
|
147
|
+
- "На больших дочерних таблицах это может вызвать серьёзную конкуренцию блокировок и замедлить каскадные операции."
|
|
148
|
+
- "Индекс должен иметь FK-колонку как ведущую (первую) для эффективности."
|
|
149
|
+
- "Маленькие таблицы (< 10K строк) могут не выиграть от добавления индекса — PostgreSQL предпочтёт seq scan."
|
|
150
|
+
|
|
151
|
+
index_correlation:
|
|
152
|
+
title: "Index Correlation"
|
|
153
|
+
what: "Индексы, где физический порядок строк плохо соответствует порядку индекса."
|
|
154
|
+
how: "Читает pg_stats.correlation для ведущих колонок индексов. Корреляция около 0 означает случайный физический порядок относительно индекса, что вызывает избыточный random I/O при range scan."
|
|
155
|
+
nuances:
|
|
156
|
+
- "Корреляция от -1 до 1. Значения около 0 — случайный порядок; около 1 или -1 — упорядоченный."
|
|
157
|
+
- "Низкая корреляция в основном влияет на range scan (BETWEEN, >, <) и ORDER BY — точечные поиски затронуты меньше."
|
|
158
|
+
- "CLUSTER table USING index физически переупорядочивает строки, но блокирует таблицу и не поддерживается автоматически."
|
|
159
|
+
- "Для append-only таблиц с timestamp колонками корреляция естественно высокая — действий не требуется."
|
|
160
|
+
- "Показаны только таблицы > 10MB с > 100 index scan для снижения шума."
|
|
161
|
+
|
|
120
162
|
index_sizes:
|
|
121
163
|
title: "Index Sizes"
|
|
122
164
|
what: "Размеры индексов на диске."
|
|
@@ -183,6 +225,16 @@ ru:
|
|
|
183
225
|
- "Высокий seq_tup_read/seq_scan = много строк за один scan = возможно норма."
|
|
184
226
|
- "Низкий seq_tup_read/seq_scan = много scan маленьких объёмов = возможно N+1."
|
|
185
227
|
|
|
228
|
+
tables_without_pk:
|
|
229
|
+
title: "Tables Without Primary Keys"
|
|
230
|
+
what: "Таблицы без первичного ключа."
|
|
231
|
+
how: "Проверяет pg_index на отсутствие indisprimary записей для пользовательских таблиц."
|
|
232
|
+
nuances:
|
|
233
|
+
- "Логическая репликация требует первичный ключ или REPLICA IDENTITY для идентификации строк."
|
|
234
|
+
- "Без PK операции UPDATE и DELETE требуют иного способа уникальной идентификации строк, часто приводя к полным сканам таблицы."
|
|
235
|
+
- "Join-таблицы (many-to-many) часто намеренно без PK — рассмотрите добавление составного PK."
|
|
236
|
+
- "Некоторые ORM (например, Rails) предполагают наличие 'id' первичного ключа — таблицы без него могут вызвать ошибки фреймворка."
|
|
237
|
+
|
|
186
238
|
recently_modified:
|
|
187
239
|
title: "Recently Modified"
|
|
188
240
|
what: "Таблицы с недавней активностью INSERT/UPDATE/DELETE."
|
|
@@ -326,6 +378,28 @@ ru:
|
|
|
326
378
|
- "Полезно для быстрой оценки состояния базы."
|
|
327
379
|
- "Сравнивайте с baseline для выявления аномалий."
|
|
328
380
|
|
|
381
|
+
wraparound_risk:
|
|
382
|
+
title: "Wraparound Risk"
|
|
383
|
+
what: "Близость возраста Transaction ID к лимиту wraparound в 2 миллиарда."
|
|
384
|
+
how: "Читает age(datfrozenxid) из pg_database. Когда значение приближается к 2^31 (~2.1 млрд), PostgreSQL остановится для предотвращения повреждения данных."
|
|
385
|
+
nuances:
|
|
386
|
+
- "autovacuum_freeze_max_age (по умолчанию 200M) автоматически запускает агрессивный anti-wraparound VACUUM."
|
|
387
|
+
- "Если age превышает freeze_max_age, anti-wraparound VACUUM уже должен работать — если нет, расследуйте причину."
|
|
388
|
+
- "Долгоживущие транзакции не дают VACUUM продвинуть frozen XID — мониторьте idle-in-transaction."
|
|
389
|
+
- "В экстренных случаях запустите VACUUM FREEZE на самых больших/старых таблицах первыми."
|
|
390
|
+
- "Pct > 50% — предупреждение; > 75% — критично, требует немедленных действий."
|
|
391
|
+
|
|
392
|
+
checkpoint_stats:
|
|
393
|
+
title: "Checkpoint Stats"
|
|
394
|
+
what: "Частота чекпоинтов и метрики производительности background writer."
|
|
395
|
+
how: "Данные из pg_stat_bgwriter показывают количество чекпоинтов, тайминги и распределение записи буферов."
|
|
396
|
+
nuances:
|
|
397
|
+
- "checkpoints_timed = запланированные чекпоинты (нормально); checkpoints_req = вынужденные чекпоинты (под нагрузкой)."
|
|
398
|
+
- "Высокий requested_pct означает, что WAL заполняется до checkpoint_timeout — увеличьте max_wal_size."
|
|
399
|
+
- "buffers_backend > 0 означает, что бэкенды сами пишут грязные буферы — увеличьте shared_buffers или активность bgwriter."
|
|
400
|
+
- "bgwriter_stops (maxwritten_clean) > 0 означает, что bgwriter достиг лимита за раунд — увеличьте bgwriter_lru_maxpages."
|
|
401
|
+
- "Статистика накапливается с момента stats_reset — сравнивайте за периоды для осмысленного анализа."
|
|
402
|
+
|
|
329
403
|
cache_stats:
|
|
330
404
|
title: "Cache Stats"
|
|
331
405
|
what: "Статистика кэширования базы данных."
|
|
@@ -356,6 +430,13 @@ ru:
|
|
|
356
430
|
low_cache_hit: "Низкий cache hit ratio. Запрос часто читает с диска вместо кэша."
|
|
357
431
|
high_seq_scan: "Много sequential scan. Возможно не хватает индекса."
|
|
358
432
|
unused_index: "Индекс не используется. Кандидат на удаление."
|
|
433
|
+
inefficient_index: "Индекс читает гораздо больше записей, чем извлекает. Вероятно, порядок колонок составного индекса не соответствует предикатам запроса."
|
|
434
|
+
fk_without_index: "FK-колонка без поддерживающего индекса. DELETE/UPDATE родительской таблицы вызовет sequential scan."
|
|
435
|
+
low_correlation: "Низкая физическая корреляция между индексом и порядком строк. Range scan вызовет избыточный random I/O."
|
|
436
|
+
temp_file_heavy: "Запрос сбрасывает данные во временные файлы на диск. Рассмотрите увеличение work_mem или оптимизацию запроса."
|
|
437
|
+
missing_pk: "Таблица без первичного ключа. Это ломает логическую репликацию и может вызвать проблемы с ORM."
|
|
438
|
+
wraparound_risk: "Возраст Transaction ID приближается к лимиту wraparound. Требуется VACUUM FREEZE."
|
|
439
|
+
high_checkpoint_req: "Высокий процент вынужденных чекпоинтов. Рассмотрите увеличение max_wal_size."
|
|
359
440
|
high_bloat: "Высокий bloat. Требуется REINDEX или VACUUM."
|
|
360
441
|
many_dead_tuples: "Много мёртвых строк. Требуется VACUUM."
|
|
361
442
|
long_running: "Долго выполняющийся запрос. Может блокировать другие операции."
|
data/config/locales/uk.yml
CHANGED
|
@@ -51,6 +51,16 @@ uk:
|
|
|
51
51
|
- "Збільшення shared_buffers допомагає, але є межа ефективності (зазвичай 25% RAM)."
|
|
52
52
|
- "Covering indexes (INCLUDE) дозволяють виконувати index-only scan без звернення до таблиці."
|
|
53
53
|
|
|
54
|
+
temp_file_queries:
|
|
55
|
+
title: "Temp File Queries"
|
|
56
|
+
what: "Запити, що скидають проміжні результати у тимчасові файли на диск."
|
|
57
|
+
how: "Аналізує temp_blks_written та temp_blks_read з pg_stat_statements. Тимчасові файли створюються, коли work_mem недостатній для сортування, хешування або матеріалізації."
|
|
58
|
+
nuances:
|
|
59
|
+
- "Запис у тимчасові файли на порядки повільніший за операції в пам'яті."
|
|
60
|
+
- "Збільшення work_mem може усунути тимчасові файли, але впливає на всі сесії — використовуйте SET LOCAL для конкретних запитів."
|
|
61
|
+
- "Часті причини: великі сортування (ORDER BY), hash join на великих таблицях, DISTINCT на багатьох рядках, складні CTE."
|
|
62
|
+
- "Розгляньте додавання індексів для усунення сортувань або переписування запитів для зменшення проміжних результатів."
|
|
63
|
+
|
|
54
64
|
all_queries:
|
|
55
65
|
title: "All Queries"
|
|
56
66
|
what: "Повна статистика по всіх запитах з pg_stat_statements."
|
|
@@ -107,6 +117,17 @@ uk:
|
|
|
107
117
|
- "idx_tup_read — рядки прочитані з індексу."
|
|
108
118
|
- "idx_tup_fetch — рядки отримані з таблиці після index scan (для non-covering indexes)."
|
|
109
119
|
|
|
120
|
+
inefficient_indexes:
|
|
121
|
+
title: "Inefficient Indexes"
|
|
122
|
+
what: "Індекси, які використовуються, але сканують значно більше записів, ніж реально витягують."
|
|
123
|
+
how: "Порівнює idx_tup_read (записів прочитано з індексу) та idx_tup_fetch (рядків витягнуто з heap) з pg_stat_user_indexes. Високе співвідношення означає, що порядок колонок індексу не відповідає предикатам запиту, змушуючи PostgreSQL сканувати великі діапазони індексу."
|
|
124
|
+
nuances:
|
|
125
|
+
- "Співвідношення read/fetch >10 означає, що індекс читає в 10+ разів більше записів, ніж повертає — явна ознака неправильного порядку колонок."
|
|
126
|
+
- "Для складених індексів (a, b, c) запити, що фільтрують по (b) або (c) без (a), не можуть виконати точний seek і змушені сканувати широкі діапазони."
|
|
127
|
+
- "Рішення: створити цільовий індекс з колонками, що відповідають найбільш селективним WHERE-предикатам у першу чергу."
|
|
128
|
+
- "Використовуйте EXPLAIN ANALYZE для підтвердження, що index scan читає надлишкову кількість записів, перш ніж вносити зміни."
|
|
129
|
+
- "Index-only scans (де idx_tup_fetch = 0) виключені — вони вказують на ефективно працюючі covering indexes."
|
|
130
|
+
|
|
110
131
|
bloated_indexes:
|
|
111
132
|
title: "Bloated Indexes"
|
|
112
133
|
what: "Індекси з високим рівнем bloat (роздування) через мертві кортежі."
|
|
@@ -117,6 +138,27 @@ uk:
|
|
|
117
138
|
- "pg_repack дозволяє перебудувати індекси без блокувань."
|
|
118
139
|
- "Bloat >30-50% — привід для дій."
|
|
119
140
|
|
|
141
|
+
fk_without_indexes:
|
|
142
|
+
title: "FK Without Indexes"
|
|
143
|
+
what: "Зовнішні ключі на дочірніх таблицях без підтримуючого індексу."
|
|
144
|
+
how: "Порівнює pg_constraint (зовнішні ключі) з pg_index для пошуку FK-колонок без відповідного ведучого індексу."
|
|
145
|
+
nuances:
|
|
146
|
+
- "Без індексу DELETE або UPDATE батьківської таблиці викликає sequential scan дочірньої таблиці."
|
|
147
|
+
- "На великих дочірніх таблицях це може спричинити серйозну конкуренцію блокувань та сповільнити каскадні операції."
|
|
148
|
+
- "Індекс повинен мати FK-колонку як ведучу (першу) для ефективності."
|
|
149
|
+
- "Маленькі таблиці (< 10K рядків) можуть не виграти від додавання індексу — PostgreSQL віддасть перевагу seq scan."
|
|
150
|
+
|
|
151
|
+
index_correlation:
|
|
152
|
+
title: "Index Correlation"
|
|
153
|
+
what: "Індекси, де фізичний порядок рядків погано відповідає порядку індексу."
|
|
154
|
+
how: "Читає pg_stats.correlation для ведучих колонок індексів. Кореляція близько 0 означає випадковий фізичний порядок відносно індексу, що спричиняє надлишковий random I/O при range scan."
|
|
155
|
+
nuances:
|
|
156
|
+
- "Кореляція від -1 до 1. Значення близько 0 — випадковий порядок; близько 1 або -1 — впорядкований."
|
|
157
|
+
- "Низька кореляція переважно впливає на range scan (BETWEEN, >, <) та ORDER BY — точкові пошуки зачіпаються менше."
|
|
158
|
+
- "CLUSTER table USING index фізично переупорядковує рядки, але блокує таблицю та не підтримується автоматично."
|
|
159
|
+
- "Для append-only таблиць з timestamp колонками кореляція природно висока — дій не потрібно."
|
|
160
|
+
- "Показані лише таблиці > 10MB з > 100 index scan для зниження шуму."
|
|
161
|
+
|
|
120
162
|
index_sizes:
|
|
121
163
|
title: "Index Sizes"
|
|
122
164
|
what: "Розміри індексів на диску."
|
|
@@ -183,6 +225,16 @@ uk:
|
|
|
183
225
|
- "Високий seq_tup_read/seq_scan = багато рядків за один scan = можливо норма."
|
|
184
226
|
- "Низький seq_tup_read/seq_scan = багато scan маленьких об'ємів = можливо N+1."
|
|
185
227
|
|
|
228
|
+
tables_without_pk:
|
|
229
|
+
title: "Tables Without Primary Keys"
|
|
230
|
+
what: "Таблиці без первинного ключа."
|
|
231
|
+
how: "Перевіряє pg_index на відсутність indisprimary записів для користувацьких таблиць."
|
|
232
|
+
nuances:
|
|
233
|
+
- "Логічна реплікація потребує первинний ключ або REPLICA IDENTITY для ідентифікації рядків."
|
|
234
|
+
- "Без PK операції UPDATE та DELETE потребують іншого способу унікальної ідентифікації рядків, часто призводячи до повних сканів таблиці."
|
|
235
|
+
- "Join-таблиці (many-to-many) часто навмисно без PK — розгляньте додавання складеного PK."
|
|
236
|
+
- "Деякі ORM (наприклад, Rails) передбачають наявність 'id' первинного ключа — таблиці без нього можуть спричинити помилки фреймворку."
|
|
237
|
+
|
|
186
238
|
recently_modified:
|
|
187
239
|
title: "Recently Modified"
|
|
188
240
|
what: "Таблиці з недавньою активністю INSERT/UPDATE/DELETE."
|
|
@@ -249,6 +301,46 @@ uk:
|
|
|
249
301
|
- "Занадто багато idle = застосунок не закриває з'єднання або пул занадто великий."
|
|
250
302
|
- "idle_session_timeout (PostgreSQL 14+) може автоматично закривати idle з'єднання."
|
|
251
303
|
|
|
304
|
+
pool_usage:
|
|
305
|
+
title: "Використання пулу з'єднань"
|
|
306
|
+
what: "Поточне використання пулу з'єднань з показниками активних, idle та доступних з'єднань по базах даних."
|
|
307
|
+
how: "Аналіз станів з'єднань в pg_stat_activity та порівняння з лімітом max_connections."
|
|
308
|
+
nuances:
|
|
309
|
+
- "Утилізація вище 70% означає наближення до ліміту — розгляньте масштабування."
|
|
310
|
+
- "Idle in transaction з'єднання витрачають ресурси та блокують VACUUM."
|
|
311
|
+
- "max_connections — глобальне налаштування для всієї БД, а не для кожної бази окремо."
|
|
312
|
+
- "Connection pooler'и (PgBouncer/pgpool) дозволяють мати більше з'єднань на рівні застосунку."
|
|
313
|
+
|
|
314
|
+
pool_wait_times:
|
|
315
|
+
title: "Аналіз часу очікування"
|
|
316
|
+
what: "Запити, що очікують ресурсів (блокування, I/O, мережа)."
|
|
317
|
+
how: "Аналіз wait_event та wait_event_type з pg_stat_activity для не-idle з'єднань."
|
|
318
|
+
nuances:
|
|
319
|
+
- "ClientRead очікування = повільний клієнт не встигає споживати дані."
|
|
320
|
+
- "Lock очікування = конкуренція між конкурентними запитами."
|
|
321
|
+
- "IO очікування = проблеми продуктивності диска або недостатній кеш."
|
|
322
|
+
- "Очікування понад 60 секунд критичні та потребують негайного розслідування."
|
|
323
|
+
|
|
324
|
+
pool_saturation:
|
|
325
|
+
title: "Попередження про насичення пулу"
|
|
326
|
+
what: "Загальні метрики здоров'я пулу з'єднань з попередженнями про насичення та рекомендаціями."
|
|
327
|
+
how: "Розрахунок відсотків утилізації для total, active, idle та проблемних з'єднань."
|
|
328
|
+
nuances:
|
|
329
|
+
- "Постійна утилізація вище 70% = необхідність налаштування пулу або масштабування."
|
|
330
|
+
- "Висока кількість idle in transaction = проблеми обробки транзакцій застосунком."
|
|
331
|
+
- "superuser_reserved_connections зменшують доступну ємність пулу."
|
|
332
|
+
- "Відстежуйте тренди — різкі стрибки можуть вказувати на витоки з'єднань."
|
|
333
|
+
|
|
334
|
+
connection_churn:
|
|
335
|
+
title: "Аналіз оборотності з'єднань"
|
|
336
|
+
what: "Аналіз патернів життєвого циклу з'єднань для виявлення надлишкового churn (часте підключення/відключення)."
|
|
337
|
+
how: "Вивчення віку з'єднань для ідентифікації короткоживучих з'єднань та розрахунку churn rate по застосунках."
|
|
338
|
+
nuances:
|
|
339
|
+
- "З'єднання молодші 10 секунд = короткоживучі."
|
|
340
|
+
- "Churn rate вище 50% = відсутність або неправильне налаштування connection pooling."
|
|
341
|
+
- "Багато коротких з'єднань = збільшене навантаження на CPU та автентифікацію."
|
|
342
|
+
- "Веб-застосунки повинні підтримувати пул з'єднань, а не створювати з'єднання на кожен запит."
|
|
343
|
+
|
|
252
344
|
# === SYSTEM ===
|
|
253
345
|
database_sizes:
|
|
254
346
|
title: "Database Sizes"
|
|
@@ -286,6 +378,28 @@ uk:
|
|
|
286
378
|
- "Корисно для швидкої оцінки стану бази."
|
|
287
379
|
- "Порівнюйте з baseline для виявлення аномалій."
|
|
288
380
|
|
|
381
|
+
wraparound_risk:
|
|
382
|
+
title: "Wraparound Risk"
|
|
383
|
+
what: "Близькість віку Transaction ID до ліміту wraparound у 2 мільярди."
|
|
384
|
+
how: "Читає age(datfrozenxid) з pg_database. Коли значення наближається до 2^31 (~2.1 млрд), PostgreSQL зупиниться для запобігання пошкодження даних."
|
|
385
|
+
nuances:
|
|
386
|
+
- "autovacuum_freeze_max_age (за замовчуванням 200M) автоматично запускає агресивний anti-wraparound VACUUM."
|
|
387
|
+
- "Якщо age перевищує freeze_max_age, anti-wraparound VACUUM вже повинен працювати — якщо ні, розслідуйте причину."
|
|
388
|
+
- "Довготривалі транзакції не дають VACUUM просунути frozen XID — моніторте idle-in-transaction."
|
|
389
|
+
- "В екстрених випадках запустіть VACUUM FREEZE на найбільших/найстаріших таблицях першими."
|
|
390
|
+
- "Pct > 50% — попередження; > 75% — критично, потребує негайних дій."
|
|
391
|
+
|
|
392
|
+
checkpoint_stats:
|
|
393
|
+
title: "Checkpoint Stats"
|
|
394
|
+
what: "Частота чекпоінтів та метрики продуктивності background writer."
|
|
395
|
+
how: "Дані з pg_stat_bgwriter показують кількість чекпоінтів, тайминги та розподіл запису буферів."
|
|
396
|
+
nuances:
|
|
397
|
+
- "checkpoints_timed = заплановані чекпоінти (нормально); checkpoints_req = вимушені чекпоінти (під навантаженням)."
|
|
398
|
+
- "Високий requested_pct означає, що WAL заповнюється до checkpoint_timeout — збільште max_wal_size."
|
|
399
|
+
- "buffers_backend > 0 означає, що бекенди самі пишуть брудні буфери — збільште shared_buffers або активність bgwriter."
|
|
400
|
+
- "bgwriter_stops (maxwritten_clean) > 0 означає, що bgwriter досяг ліміту за раунд — збільште bgwriter_lru_maxpages."
|
|
401
|
+
- "Статистика накопичується з моменту stats_reset — порівнюйте за періоди для осмисленого аналізу."
|
|
402
|
+
|
|
289
403
|
cache_stats:
|
|
290
404
|
title: "Cache Stats"
|
|
291
405
|
what: "Статистика кешування бази даних."
|
|
@@ -316,8 +430,20 @@ uk:
|
|
|
316
430
|
low_cache_hit: "Низький cache hit ratio. Запит часто читає з диска замість кешу."
|
|
317
431
|
high_seq_scan: "Багато sequential scan. Можливо не вистачає індексу."
|
|
318
432
|
unused_index: "Індекс не використовується. Кандидат на видалення."
|
|
433
|
+
inefficient_index: "Індекс читає значно більше записів, ніж витягує. Ймовірно, порядок колонок складеного індексу не відповідає предикатам запиту."
|
|
434
|
+
fk_without_index: "FK-колонка без підтримуючого індексу. DELETE/UPDATE батьківської таблиці спричинить sequential scan."
|
|
435
|
+
low_correlation: "Низька фізична кореляція між індексом та порядком рядків. Range scan спричинить надлишковий random I/O."
|
|
436
|
+
temp_file_heavy: "Запит скидає дані у тимчасові файли на диск. Розгляньте збільшення work_mem або оптимізацію запиту."
|
|
437
|
+
missing_pk: "Таблиця без первинного ключа. Це ламає логічну реплікацію та може спричинити проблеми з ORM."
|
|
438
|
+
wraparound_risk: "Вік Transaction ID наближається до ліміту wraparound. Потрібен VACUUM FREEZE."
|
|
439
|
+
high_checkpoint_req: "Високий відсоток вимушених чекпоінтів. Розгляньте збільшення max_wal_size."
|
|
319
440
|
high_bloat: "Високий bloat. Потрібен REINDEX або VACUUM."
|
|
320
441
|
many_dead_tuples: "Багато мертвих рядків. Потрібен VACUUM."
|
|
321
442
|
long_running: "Довго виконуваний запит. Може блокувати інші операції."
|
|
322
443
|
blocking: "Блокує інші запити. Потребує уваги."
|
|
323
444
|
idle_in_transaction: "Відкрита транзакція без активності. Блокує VACUUM та утримує локи."
|
|
445
|
+
high_pool_usage: "Висока утилізація пулу з'єднань. Збільште max_connections або впровадьте connection pooling."
|
|
446
|
+
long_wait_time: "Запит занадто довго очікує ресурсів. Перевірте конкуренцію блокувань або проблеми I/O."
|
|
447
|
+
pool_saturation: "Пул з'єднань насичений. Ризик вичерпання з'єднань та помилок застосунку."
|
|
448
|
+
high_connection_churn: "Висока оборотність з'єднань. Впровадьте connection pooling для зниження накладних витрат."
|
|
449
|
+
too_many_short_connections: "Занадто багато короткоживучих з'єднань. Застосунок повинен перевикористовувати з'єднання через pooling."
|