pg_reports 0.6.0 → 0.6.2
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 +45 -0
- data/README.md +143 -378
- data/app/controllers/pg_reports/dashboard_controller.rb +21 -21
- data/app/views/layouts/pg_reports/application.html.erb +65 -8
- data/app/views/pg_reports/dashboard/_show_modals.html.erb +22 -22
- data/app/views/pg_reports/dashboard/_show_scripts.html.erb +55 -57
- data/app/views/pg_reports/dashboard/_show_styles.html.erb +18 -0
- data/app/views/pg_reports/dashboard/index.html.erb +109 -106
- data/app/views/pg_reports/dashboard/show.html.erb +26 -26
- data/config/locales/en.yml +488 -0
- data/config/locales/ru.yml +481 -0
- data/config/locales/uk.yml +481 -0
- data/lib/pg_reports/annotation_parser.rb +13 -1
- data/lib/pg_reports/compatibility.rb +3 -3
- data/lib/pg_reports/dashboard/reports_registry.rb +83 -12
- data/lib/pg_reports/definitions/schema_analysis/always_null_columns.yml +31 -0
- data/lib/pg_reports/definitions/schema_analysis/unused_columns.yml +32 -0
- data/lib/pg_reports/definitions/tables/unused_tables.yml +30 -0
- data/lib/pg_reports/definitions/tables/update_hotspots.yml +32 -0
- data/lib/pg_reports/module_generator.rb +2 -1
- data/lib/pg_reports/modules/schema_analysis.rb +261 -2
- data/lib/pg_reports/modules/system.rb +3 -3
- data/lib/pg_reports/query_monitor.rb +2 -6
- data/lib/pg_reports/report_definition.rb +20 -24
- data/lib/pg_reports/sql/schema_analysis/always_null_columns.sql +25 -0
- data/lib/pg_reports/sql/schema_analysis/unused_columns.sql +36 -0
- data/lib/pg_reports/sql/tables/unused_tables.sql +19 -0
- data/lib/pg_reports/sql/tables/update_hotspots.sql +26 -0
- data/lib/pg_reports/version.rb +1 -1
- metadata +9 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- Columns where ~100% of rows are NULL
|
|
2
|
+
-- Strong indicator nothing in the application populates this column anymore.
|
|
3
|
+
|
|
4
|
+
SELECT
|
|
5
|
+
s.schemaname AS schema,
|
|
6
|
+
s.tablename AS table_name,
|
|
7
|
+
s.attname AS column_name,
|
|
8
|
+
format_type(a.atttypid, a.atttypmod) AS data_type,
|
|
9
|
+
ROUND((s.null_frac * 100)::numeric, 2) AS null_pct,
|
|
10
|
+
pg_get_expr(ad.adbin, ad.adrelid) AS column_default,
|
|
11
|
+
a.attnotnull AS not_null_constraint,
|
|
12
|
+
c.reltuples::bigint AS estimated_rows
|
|
13
|
+
FROM pg_stats s
|
|
14
|
+
JOIN pg_class c ON c.relname = s.tablename
|
|
15
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = s.schemaname
|
|
16
|
+
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attname = s.attname
|
|
17
|
+
LEFT JOIN pg_attrdef ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
|
|
18
|
+
WHERE s.schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
|
19
|
+
AND c.relkind = 'r'
|
|
20
|
+
AND a.attnum > 0
|
|
21
|
+
AND NOT a.attisdropped
|
|
22
|
+
AND a.attnotnull = false
|
|
23
|
+
AND s.null_frac >= 0.999
|
|
24
|
+
AND c.reltuples > 1000
|
|
25
|
+
ORDER BY c.reltuples DESC;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
-- Columns that have only ever held a single value (likely never updated since creation)
|
|
2
|
+
-- Uses pg_stats.n_distinct = 1 as a proxy for "no UPDATE has ever changed this field".
|
|
3
|
+
-- Strong indicator the application code no longer references the column but it was never dropped.
|
|
4
|
+
|
|
5
|
+
SELECT
|
|
6
|
+
s.schemaname AS schema,
|
|
7
|
+
s.tablename AS table_name,
|
|
8
|
+
s.attname AS column_name,
|
|
9
|
+
format_type(a.atttypid, a.atttypmod) AS data_type,
|
|
10
|
+
CASE
|
|
11
|
+
WHEN s.most_common_vals IS NOT NULL
|
|
12
|
+
THEN substring((s.most_common_vals::text) FROM 1 FOR 80)
|
|
13
|
+
ELSE NULL
|
|
14
|
+
END AS sole_value,
|
|
15
|
+
pg_get_expr(ad.adbin, ad.adrelid) AS column_default,
|
|
16
|
+
ROUND((s.null_frac * 100)::numeric, 2) AS null_pct,
|
|
17
|
+
c.reltuples::bigint AS estimated_rows
|
|
18
|
+
FROM pg_stats s
|
|
19
|
+
JOIN pg_class c ON c.relname = s.tablename
|
|
20
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = s.schemaname
|
|
21
|
+
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attname = s.attname
|
|
22
|
+
LEFT JOIN pg_attrdef ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
|
|
23
|
+
WHERE s.schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
|
24
|
+
AND c.relkind = 'r'
|
|
25
|
+
AND a.attnum > 0
|
|
26
|
+
AND NOT a.attisdropped
|
|
27
|
+
AND s.n_distinct = 1
|
|
28
|
+
AND s.null_frac < 0.999
|
|
29
|
+
AND c.reltuples > 1000
|
|
30
|
+
AND NOT EXISTS (
|
|
31
|
+
SELECT 1 FROM pg_index i
|
|
32
|
+
WHERE i.indrelid = c.oid
|
|
33
|
+
AND a.attnum = ANY(i.indkey)
|
|
34
|
+
AND (i.indisprimary OR i.indisunique)
|
|
35
|
+
)
|
|
36
|
+
ORDER BY c.reltuples DESC;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- Tables that have not been read at all since the last stats reset
|
|
2
|
+
-- Zero seq_scan AND zero idx_scan -- application code never queries them.
|
|
3
|
+
-- Candidates for archival, deletion, or extraction to a separate database.
|
|
4
|
+
|
|
5
|
+
SELECT
|
|
6
|
+
t.schemaname AS schema,
|
|
7
|
+
t.relname AS table_name,
|
|
8
|
+
t.n_live_tup AS live_rows,
|
|
9
|
+
pg_size_pretty(pg_total_relation_size(t.relid)) AS total_size,
|
|
10
|
+
ROUND(pg_total_relation_size(t.relid) / 1024.0 / 1024.0, 2) AS total_size_mb,
|
|
11
|
+
COALESCE(t.last_autoanalyze, t.last_analyze) AS last_analyzed,
|
|
12
|
+
d.stats_reset AS db_stats_since
|
|
13
|
+
FROM pg_stat_user_tables t
|
|
14
|
+
LEFT JOIN pg_stat_database d ON d.datname = current_database()
|
|
15
|
+
WHERE t.schemaname NOT IN ('pg_catalog', 'information_schema')
|
|
16
|
+
AND t.seq_scan = 0
|
|
17
|
+
AND COALESCE(t.idx_scan, 0) = 0
|
|
18
|
+
AND t.n_live_tup > 0
|
|
19
|
+
ORDER BY pg_total_relation_size(t.relid) DESC;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- Tables with disproportionately high write activity
|
|
2
|
+
-- updates_per_row = n_tup_upd / n_live_tup -- same rows being updated repeatedly
|
|
3
|
+
-- hot_update_pct = n_tup_hot_upd / n_tup_upd -- low value means indexed columns are being updated (expensive)
|
|
4
|
+
|
|
5
|
+
SELECT
|
|
6
|
+
schemaname AS schema,
|
|
7
|
+
relname AS table_name,
|
|
8
|
+
n_live_tup AS live_rows,
|
|
9
|
+
n_tup_upd AS updates,
|
|
10
|
+
n_tup_hot_upd AS hot_updates,
|
|
11
|
+
CASE WHEN n_tup_upd > 0
|
|
12
|
+
THEN ROUND((n_tup_hot_upd::numeric / n_tup_upd) * 100, 2)
|
|
13
|
+
ELSE 0
|
|
14
|
+
END AS hot_update_pct,
|
|
15
|
+
CASE WHEN n_live_tup > 0
|
|
16
|
+
THEN ROUND(n_tup_upd::numeric / n_live_tup, 2)
|
|
17
|
+
ELSE 0
|
|
18
|
+
END AS updates_per_row,
|
|
19
|
+
n_tup_ins AS inserts,
|
|
20
|
+
n_tup_del AS deletes,
|
|
21
|
+
n_dead_tup AS dead_rows
|
|
22
|
+
FROM pg_stat_user_tables
|
|
23
|
+
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
|
|
24
|
+
AND n_tup_upd > 1000
|
|
25
|
+
AND n_live_tup > 100
|
|
26
|
+
ORDER BY (n_tup_upd::numeric / GREATEST(n_live_tup, 1)) DESC;
|
data/lib/pg_reports/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_reports
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eldar Avatov
|
|
@@ -191,6 +191,8 @@ files:
|
|
|
191
191
|
- lib/pg_reports/definitions/queries/missing_index_queries.yml
|
|
192
192
|
- lib/pg_reports/definitions/queries/slow_queries.yml
|
|
193
193
|
- lib/pg_reports/definitions/queries/temp_file_queries.yml
|
|
194
|
+
- lib/pg_reports/definitions/schema_analysis/always_null_columns.yml
|
|
195
|
+
- lib/pg_reports/definitions/schema_analysis/unused_columns.yml
|
|
194
196
|
- lib/pg_reports/definitions/system/activity_overview.yml
|
|
195
197
|
- lib/pg_reports/definitions/system/cache_stats.yml
|
|
196
198
|
- lib/pg_reports/definitions/system/database_sizes.yml
|
|
@@ -204,6 +206,8 @@ files:
|
|
|
204
206
|
- lib/pg_reports/definitions/tables/seq_scans.yml
|
|
205
207
|
- lib/pg_reports/definitions/tables/table_sizes.yml
|
|
206
208
|
- lib/pg_reports/definitions/tables/tables_without_pk.yml
|
|
209
|
+
- lib/pg_reports/definitions/tables/unused_tables.yml
|
|
210
|
+
- lib/pg_reports/definitions/tables/update_hotspots.yml
|
|
207
211
|
- lib/pg_reports/definitions/tables/vacuum_needed.yml
|
|
208
212
|
- lib/pg_reports/engine.rb
|
|
209
213
|
- lib/pg_reports/error.rb
|
|
@@ -248,7 +252,9 @@ files:
|
|
|
248
252
|
- lib/pg_reports/sql/queries/missing_index_queries.sql
|
|
249
253
|
- lib/pg_reports/sql/queries/slow_queries.sql
|
|
250
254
|
- lib/pg_reports/sql/queries/temp_file_queries.sql
|
|
255
|
+
- lib/pg_reports/sql/schema_analysis/always_null_columns.sql
|
|
251
256
|
- lib/pg_reports/sql/schema_analysis/unique_indexes.sql
|
|
257
|
+
- lib/pg_reports/sql/schema_analysis/unused_columns.sql
|
|
252
258
|
- lib/pg_reports/sql/system/activity_overview.sql
|
|
253
259
|
- lib/pg_reports/sql/system/cache_stats.sql
|
|
254
260
|
- lib/pg_reports/sql/system/checkpoint_stats.sql
|
|
@@ -266,6 +272,8 @@ files:
|
|
|
266
272
|
- lib/pg_reports/sql/tables/seq_scans.sql
|
|
267
273
|
- lib/pg_reports/sql/tables/table_sizes.sql
|
|
268
274
|
- lib/pg_reports/sql/tables/tables_without_pk.sql
|
|
275
|
+
- lib/pg_reports/sql/tables/unused_tables.sql
|
|
276
|
+
- lib/pg_reports/sql/tables/update_hotspots.sql
|
|
269
277
|
- lib/pg_reports/sql/tables/vacuum_needed.sql
|
|
270
278
|
- lib/pg_reports/sql_loader.rb
|
|
271
279
|
- lib/pg_reports/telegram_sender.rb
|