pg-stats 1.0.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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/executables/pg-stats-bloat +7 -0
  3. data/executables/pg-stats-blocking-queries +7 -0
  4. data/executables/pg-stats-cache-hit-rate +7 -0
  5. data/executables/pg-stats-extensions +7 -0
  6. data/executables/pg-stats-index-size +7 -0
  7. data/executables/pg-stats-index-usage +7 -0
  8. data/executables/pg-stats-locks +7 -0
  9. data/executables/pg-stats-long-running-queries +7 -0
  10. data/executables/pg-stats-outliers +7 -0
  11. data/executables/pg-stats-records-rank +7 -0
  12. data/executables/pg-stats-seq-scans +7 -0
  13. data/executables/pg-stats-slow-statements +7 -0
  14. data/executables/pg-stats-statements-reset +7 -0
  15. data/executables/pg-stats-table-indexes-size +7 -0
  16. data/executables/pg-stats-table-size +7 -0
  17. data/executables/pg-stats-total-index-size +7 -0
  18. data/executables/pg-stats-total-table-size +7 -0
  19. data/executables/pg-stats-unused-indexes +7 -0
  20. data/executables/pg-stats-vacuum +7 -0
  21. data/queries/MIT-License.txt +20 -0
  22. data/queries/bloat.sql +63 -0
  23. data/queries/blocking-queries.sql +16 -0
  24. data/queries/cache-hit-rate.sql +11 -0
  25. data/queries/extensions.sql +4 -0
  26. data/queries/index-size.sql +11 -0
  27. data/queries/index-usage.sql +12 -0
  28. data/queries/locks.sql +16 -0
  29. data/queries/long-running-queries.sql +14 -0
  30. data/queries/outliers.sql +10 -0
  31. data/queries/records-rank.sql +9 -0
  32. data/queries/seq-scans.sql +7 -0
  33. data/queries/slow-statements.sql +9 -0
  34. data/queries/table-indexes-size.sql +10 -0
  35. data/queries/table-size.sql +10 -0
  36. data/queries/total-index-size.sql +8 -0
  37. data/queries/total-table-size.sql +10 -0
  38. data/queries/unused-indexes.sql +16 -0
  39. data/queries/vacuum.sql +40 -0
  40. data/scripts/bloat.sh +13 -0
  41. data/scripts/blocking-queries.sh +13 -0
  42. data/scripts/cache-hit-rate.sh +13 -0
  43. data/scripts/extensions.sh +13 -0
  44. data/scripts/index-size.sh +13 -0
  45. data/scripts/index-usage.sh +13 -0
  46. data/scripts/locks.sh +13 -0
  47. data/scripts/long-running-queries.sh +13 -0
  48. data/scripts/outliers.sh +16 -0
  49. data/scripts/records-rank.sh +13 -0
  50. data/scripts/run.sh +19 -0
  51. data/scripts/seq-scans.sh +13 -0
  52. data/scripts/slow-statements.sh +16 -0
  53. data/scripts/statements-reset.sh +14 -0
  54. data/scripts/table-indexes-size.sh +13 -0
  55. data/scripts/table-size.sh +13 -0
  56. data/scripts/total-index-size.sh +13 -0
  57. data/scripts/total-table-size.sh +13 -0
  58. data/scripts/unused-indexes.sh +13 -0
  59. data/scripts/vacuum.sh +13 -0
  60. metadata +119 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2f0b03f1555456bb9186044dd2e591d03905c61a3861dec3852a7aeb2778625d
4
+ data.tar.gz: 11bc08a05d97bc1c75e2486d4e5768f6e5a50022e927c9102e889d7dbeaeccd9
5
+ SHA512:
6
+ metadata.gz: b1d30f8938922f6a7a31cb3c703bbd0348b3b7b0a38f591ab1c3483901c7a1fb194464b467d32806468012ba0625fbe72416225022be034af9e22908033a25da
7
+ data.tar.gz: db963d167755e828781bf57cffa49a6a13943899000ff4c2ea9bd671c079f92d9424f017d3e2c4935324ec5f676a7cafc4770fd97f08212a5366880e4a08c1d4
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'bloat.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'blocking-queries.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'cache-hit.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'extensions.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'index-size.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'index-usage.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'locks.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'long-running-queries.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'outliers.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'records-rank.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'seq-scans.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'slow-statements.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'statements-reset.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'table-indexes-size.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'table-size.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'total-index-size.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'total-table-size.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'unused-indexes.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../scripts', __dir__
4
+ script_filename = 'vacuum.sh'
5
+ script_filepath = File.join root, script_filename
6
+
7
+ system script_filepath
@@ -0,0 +1,20 @@
1
+ Copyright © Paweł Urbanek 2019
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/queries/bloat.sql ADDED
@@ -0,0 +1,63 @@
1
+ /* Table and index bloat in your database ordered by most wasteful */
2
+
3
+ WITH constants AS (
4
+ SELECT current_setting('block_size')::numeric AS bs, 23 AS hdr, 4 AS ma
5
+ ), bloat_info AS (
6
+ SELECT
7
+ ma,bs,schemaname,tablename,
8
+ (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
9
+ (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
10
+ FROM (
11
+ SELECT
12
+ schemaname, tablename, hdr, ma, bs,
13
+ SUM((1-null_frac)*avg_width) AS datawidth,
14
+ MAX(null_frac) AS maxfracsum,
15
+ hdr+(
16
+ SELECT 1+count(*)/8
17
+ FROM pg_stats s2
18
+ WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
19
+ ) AS nullhdr
20
+ FROM pg_stats s, constants
21
+ GROUP BY 1,2,3,4,5
22
+ ) AS foo
23
+ ), table_bloat AS (
24
+ SELECT
25
+ schemaname, tablename, cc.relpages, bs,
26
+ CEIL((cc.reltuples*((datahdr+ma-
27
+ (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta
28
+ FROM bloat_info
29
+ JOIN pg_class cc ON cc.relname = bloat_info.tablename
30
+ JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
31
+ ), index_bloat AS (
32
+ SELECT
33
+ schemaname, tablename, bs,
34
+ COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
35
+ COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
36
+ FROM bloat_info
37
+ JOIN pg_class cc ON cc.relname = bloat_info.tablename
38
+ JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
39
+ JOIN pg_index i ON indrelid = cc.oid
40
+ JOIN pg_class c2 ON c2.oid = i.indexrelid
41
+ )
42
+ SELECT
43
+ type, schemaname, object_name, bloat, pg_size_pretty(raw_waste) as waste
44
+ FROM
45
+ (SELECT
46
+ 'table' as type,
47
+ schemaname,
48
+ tablename as object_name,
49
+ ROUND(CASE WHEN otta=0 THEN 0.0 ELSE table_bloat.relpages/otta::numeric END,1) AS bloat,
50
+ CASE WHEN relpages < otta THEN '0' ELSE (bs*(table_bloat.relpages-otta)::bigint)::bigint END AS raw_waste
51
+ FROM
52
+ table_bloat
53
+ UNION
54
+ SELECT
55
+ 'index' as type,
56
+ schemaname,
57
+ tablename || '::' || iname as object_name,
58
+ ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::numeric END,1) AS bloat,
59
+ CASE WHEN ipages < iotta THEN '0' ELSE (bs*(ipages-iotta))::bigint END AS raw_waste
60
+ FROM
61
+ index_bloat) bloat_summary
62
+ ORDER BY raw_waste DESC, bloat DESC;
63
+
@@ -0,0 +1,16 @@
1
+ /* Queries holding locks which other queries are waiting to be released */
2
+
3
+ SELECT bl.pid AS blocked_pid,
4
+ ka.query AS blocking_statement,
5
+ now() - ka.query_start AS blocking_duration,
6
+ kl.pid AS blocking_pid,
7
+ a.query AS blocked_statement,
8
+ now() - a.query_start AS blocked_duration
9
+ FROM pg_catalog.pg_locks bl
10
+ JOIN pg_catalog.pg_stat_activity a
11
+ ON bl.pid = a.pid
12
+ JOIN pg_catalog.pg_locks kl
13
+ JOIN pg_catalog.pg_stat_activity ka
14
+ ON kl.pid = ka.pid
15
+ ON bl.transactionid = kl.transactionid AND bl.pid != kl.pid
16
+ WHERE NOT bl.granted;
@@ -0,0 +1,11 @@
1
+ /* Index and table hit rate */
2
+
3
+ SELECT
4
+ 'index hit rate' AS name,
5
+ (sum(idx_blks_hit)) / nullif(sum(idx_blks_hit + idx_blks_read),0) AS ratio
6
+ FROM pg_statio_user_indexes
7
+ UNION ALL
8
+ SELECT
9
+ 'table hit rate' AS name,
10
+ sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read),0) AS ratio
11
+ FROM pg_statio_user_tables;
@@ -0,0 +1,4 @@
1
+ /* Available and installed extensions */
2
+
3
+ SELECT * FROM pg_available_extensions ORDER BY name, installed_version;
4
+
@@ -0,0 +1,11 @@
1
+ /* The size of indexes, descending by size */
2
+
3
+ SELECT c.relname AS name,
4
+ pg_size_pretty(sum(c.relpages::bigint*8192)::bigint) AS size
5
+ FROM pg_class c
6
+ LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
7
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
8
+ AND n.nspname !~ '^pg_toast'
9
+ AND c.relkind='i'
10
+ GROUP BY c.relname
11
+ ORDER BY sum(c.relpages) DESC;
@@ -0,0 +1,12 @@
1
+ /* Index hit rate (effective databases are at 99% and up) */
2
+
3
+ SELECT relname,
4
+ CASE idx_scan
5
+ WHEN 0 THEN 'Insufficient data'
6
+ ELSE (100 * idx_scan / (seq_scan + idx_scan))::text
7
+ END percent_of_times_index_used,
8
+ n_live_tup rows_in_table
9
+ FROM
10
+ pg_stat_user_tables
11
+ ORDER BY
12
+ n_live_tup DESC;
data/queries/locks.sql ADDED
@@ -0,0 +1,16 @@
1
+ /* Queries with active locks */
2
+
3
+ SELECT
4
+ pg_stat_activity.pid,
5
+ pg_class.relname,
6
+ pg_locks.transactionid,
7
+ pg_locks.granted,
8
+ pg_locks.mode,
9
+ pg_stat_activity.query AS query_snippet,
10
+ age(now(),pg_stat_activity.query_start) AS "age"
11
+ FROM pg_stat_activity,pg_locks left
12
+ OUTER JOIN pg_class
13
+ ON (pg_locks.relation = pg_class.oid)
14
+ WHERE pg_stat_activity.query <> '<insufficient privilege>'
15
+ AND pg_locks.pid = pg_stat_activity.pid
16
+ AND pg_stat_activity.pid <> pg_backend_pid() order by query_start;
@@ -0,0 +1,14 @@
1
+ /* All queries longer than 1 minute by descending duration */
2
+
3
+ SELECT
4
+ pid,
5
+ now() - pg_stat_activity.query_start AS duration,
6
+ query AS query
7
+ FROM
8
+ pg_stat_activity
9
+ WHERE
10
+ pg_stat_activity.query <> ''::text
11
+ AND state <> 'idle'
12
+ AND now() - pg_stat_activity.query_start > interval '1 minute'
13
+ ORDER BY
14
+ now() - pg_stat_activity.query_start DESC;
@@ -0,0 +1,10 @@
1
+ /* 10 queries that have longest execution time in aggregate */
2
+
3
+ SELECT interval '1 millisecond' * total_time AS total_exec_time,
4
+ to_char((total_time/sum(total_time) OVER()) * 100, 'FM90D0') || '%' AS prop_exec_time,
5
+ to_char(calls, 'FM999G999G999G990') AS ncalls,
6
+ interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time,
7
+ query AS query
8
+ FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
9
+ ORDER BY total_time DESC
10
+ LIMIT 10;
@@ -0,0 +1,9 @@
1
+ /* All tables and the number of rows in each ordered by number of rows descending */
2
+
3
+ SELECT
4
+ relname AS name,
5
+ n_live_tup AS estimated_count
6
+ FROM
7
+ pg_stat_user_tables
8
+ ORDER BY
9
+ n_live_tup DESC;
@@ -0,0 +1,7 @@
1
+ /* Count of sequential scans by table descending by order */
2
+
3
+ SELECT relname AS name,
4
+ seq_scan as count
5
+ FROM
6
+ pg_stat_user_tables
7
+ ORDER BY seq_scan DESC;
@@ -0,0 +1,9 @@
1
+ /* 10 queries that have longest execution time in aggregate */
2
+
3
+ SELECT query AS qry,
4
+ interval '1 millisecond' * total_time AS exec_time,
5
+ to_char((total_time/sum(total_time) OVER()) * 100, 'FM90D0') || '%' AS prop_exec_time,
6
+ to_char(calls, 'FM999G999G990') AS ncalls,
7
+ interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time
8
+ FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
9
+ ORDER BY calls DESC LIMIT 10;
@@ -0,0 +1,10 @@
1
+ /* Total size of all the indexes on each table, descending by size */
2
+
3
+ SELECT c.relname AS table,
4
+ pg_size_pretty(pg_indexes_size(c.oid)) AS index_size
5
+ FROM pg_class c
6
+ LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
7
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
8
+ AND n.nspname !~ '^pg_toast'
9
+ AND c.relkind='r'
10
+ ORDER BY pg_indexes_size(c.oid) DESC;
@@ -0,0 +1,10 @@
1
+ /* Size of the tables (excluding indexes), descending by size */
2
+
3
+ SELECT c.relname AS name,
4
+ pg_size_pretty(pg_table_size(c.oid)) AS size
5
+ FROM pg_class c
6
+ LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
7
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
8
+ AND n.nspname !~ '^pg_toast'
9
+ AND c.relkind='r'
10
+ ORDER BY pg_table_size(c.oid) DESC;
@@ -0,0 +1,8 @@
1
+ /* Total size of all indexes in MB */
2
+
3
+ SELECT pg_size_pretty(sum(c.relpages::bigint*8192)::bigint) AS size
4
+ FROM pg_class c
5
+ LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
6
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
7
+ AND n.nspname !~ '^pg_toast'
8
+ AND c.relkind='i';
@@ -0,0 +1,10 @@
1
+ /* Size of the tables (including indexes), descending by size */
2
+
3
+ SELECT c.relname AS name,
4
+ pg_size_pretty(pg_total_relation_size(c.oid)) AS size
5
+ FROM pg_class c
6
+ LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
7
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
8
+ AND n.nspname !~ '^pg_toast'
9
+ AND c.relkind='r'
10
+ ORDER BY pg_total_relation_size(c.oid) DESC;
@@ -0,0 +1,16 @@
1
+ /* Unused and almost unused indexes */
2
+ /* Ordered by their size relative to the number of index scans.
3
+ Exclude indexes of very small tables (less than 5 pages),
4
+ where the planner will almost invariably select a sequential scan,
5
+ but may not in the future as the table grows */
6
+
7
+ SELECT
8
+ schemaname || '.' || relname AS table,
9
+ indexrelname AS index,
10
+ pg_size_pretty(pg_relation_size(i.indexrelid)) AS index_size,
11
+ idx_scan as index_scans
12
+ FROM pg_stat_user_indexes ui
13
+ JOIN pg_index i ON ui.indexrelid = i.indexrelid
14
+ WHERE NOT indisunique AND idx_scan < 50 AND pg_relation_size(relid) > 5 * 8192
15
+ ORDER BY pg_relation_size(i.indexrelid) / nullif(idx_scan, 0) DESC NULLS FIRST,
16
+ pg_relation_size(i.indexrelid) DESC;
@@ -0,0 +1,40 @@
1
+ /* Dead rows and whether an automatic vacuum is expected to be triggered */
2
+
3
+ WITH table_opts AS (
4
+ SELECT
5
+ pg_class.oid, relname, nspname, array_to_string(reloptions, '') AS relopts
6
+ FROM
7
+ pg_class INNER JOIN pg_namespace ns ON relnamespace = ns.oid
8
+ ), vacuum_settings AS (
9
+ SELECT
10
+ oid, relname, nspname,
11
+ CASE
12
+ WHEN relopts LIKE '%autovacuum_vacuum_threshold%'
13
+ THEN substring(relopts, '.*autovacuum_vacuum_threshold=([0-9.]+).*')::integer
14
+ ELSE current_setting('autovacuum_vacuum_threshold')::integer
15
+ END AS autovacuum_vacuum_threshold,
16
+ CASE
17
+ WHEN relopts LIKE '%autovacuum_vacuum_scale_factor%'
18
+ THEN substring(relopts, '.*autovacuum_vacuum_scale_factor=([0-9.]+).*')::real
19
+ ELSE current_setting('autovacuum_vacuum_scale_factor')::real
20
+ END AS autovacuum_vacuum_scale_factor
21
+ FROM
22
+ table_opts
23
+ )
24
+ SELECT
25
+ vacuum_settings.nspname AS schema,
26
+ vacuum_settings.relname AS table,
27
+ to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') AS last_vacuum,
28
+ to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
29
+ to_char(pg_class.reltuples, '9G999G999G999') AS rowcount,
30
+ to_char(psut.n_dead_tup, '9G999G999G999') AS dead_rowcount,
31
+ to_char(autovacuum_vacuum_threshold
32
+ + (autovacuum_vacuum_scale_factor::numeric * pg_class.reltuples), '9G999G999G999') AS autovacuum_threshold,
33
+ CASE
34
+ WHEN autovacuum_vacuum_threshold + (autovacuum_vacuum_scale_factor::numeric * pg_class.reltuples) < psut.n_dead_tup
35
+ THEN 'yes'
36
+ END AS expect_autovacuum
37
+ FROM
38
+ pg_stat_user_tables psut INNER JOIN pg_class ON psut.relid = pg_class.oid
39
+ INNER JOIN vacuum_settings ON pg_class.oid = vacuum_settings.oid
40
+ ORDER BY 1;
data/scripts/bloat.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Bloat"
9
+ echo "= = ="
10
+ echo "Table and index bloat in your database ordered by most wasteful"
11
+ echo
12
+
13
+ run bloat.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Blocking Queries"
9
+ echo "= = ="
10
+ echo "Queries holding locks which other queries are waiting to be released"
11
+ echo
12
+
13
+ run blocking-queries.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Cache Hit"
9
+ echo "= = ="
10
+ echo "Index and table hit rate"
11
+ echo
12
+
13
+ run cache-hit.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Extensions"
9
+ echo "= = ="
10
+ echo "Available and installed extensions"
11
+ echo
12
+
13
+ run extensions.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Index Size"
9
+ echo "= = ="
10
+ echo "The size of indexes, descending by size"
11
+ echo
12
+
13
+ run index-size.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Index Usage"
9
+ echo "= = ="
10
+ echo "Index hit rate (effective databases are at 99% and up)"
11
+ echo
12
+
13
+ run index-usage.sql
data/scripts/locks.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Locks"
9
+ echo "= = ="
10
+ echo "Queries with active locks"
11
+ echo
12
+
13
+ run locks.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Long-Running Queries"
9
+ echo "= = ="
10
+ echo "All queries longer than 1 minute by descending duration"
11
+ echo
12
+
13
+ run long-running-queries.sql
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Outliers"
9
+ echo "= = ="
10
+ echo "10 queries that have longest execution time in aggregate"
11
+ echo
12
+ echo "NOTE: Requires the pg_stats_statement extension"
13
+ echo "https://www.postgresql.org/docs/current/pgstatstatements.html"
14
+ echo
15
+
16
+ run outliers.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Records Rank"
9
+ echo "= = ="
10
+ echo "All tables and the number of rows in each ordered by number of rows descending"
11
+ echo
12
+
13
+ run records-rank.sql
data/scripts/run.sh ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ function run {
6
+ sql_file=$1
7
+
8
+ current_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
9
+ queries_dir="$current_dir/../queries"
10
+
11
+ relative_sql_file=$queries_dir/$sql_file
12
+
13
+ absolute_sql_file="$(cd "$(dirname "$relative_sql_file")"; pwd)/$(basename "$relative_sql_file")"
14
+
15
+ echo $absolute_sql_file
16
+ echo
17
+
18
+ psql -P pager=off -f $absolute_sql_file
19
+ }
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Seq Scans"
9
+ echo "= = ="
10
+ echo "Count of sequential scans by table descending by order"
11
+ echo
12
+
13
+ run seq-scans.sql
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Slow Statements"
9
+ echo "= = ="
10
+ echo "10 queries that have longest execution time in aggregate"
11
+ echo
12
+ echo "NOTE: Requires the pg_stats_statement extension"
13
+ echo "https://www.postgresql.org/docs/current/pgstatstatements.html"
14
+ echo
15
+
16
+ run slow-statements.sql
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ echo
6
+ echo "Statements Reset"
7
+ echo "= = ="
8
+ echo "Reset statements statistics data"
9
+ echo
10
+ echo "NOTE: Requires the pg_stats_statement extension"
11
+ echo "https://www.postgresql.org/docs/current/pgstatstatements.html"
12
+ echo
13
+
14
+ psql -P pager=off -c "SELECT pg_stat_statements_reset();"
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Table Indexes Size"
9
+ echo "= = ="
10
+ echo "Total size of all the indexes on each table, descending by size"
11
+ echo
12
+
13
+ run table-indexes-size.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Table Size"
9
+ echo "= = ="
10
+ echo "Size of the tables (excluding indexes), descending by size"
11
+ echo
12
+
13
+ run table-size.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Total Index Size"
9
+ echo "= = ="
10
+ echo "Total size of all indexes in MB"
11
+ echo
12
+
13
+ run total-index-size.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Total Table Size"
9
+ echo "= = ="
10
+ echo "Size of the tables (including indexes), descending by size"
11
+ echo
12
+
13
+ run total-table-size.sql
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Unused Indexes"
9
+ echo "= = ="
10
+ echo "Unused and almost unused indexes"
11
+ echo
12
+
13
+ run unused-indexes.sql
data/scripts/vacuum.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/run.sh"
6
+
7
+ echo
8
+ echo "Vacuum Stats"
9
+ echo "= = ="
10
+ echo "Dead rows and whether an automatic vacuum is expected to be triggered"
11
+ echo
12
+
13
+ run vacuum.sql
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pg-stats
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - The Eventide Project
8
+ autorequire:
9
+ bindir: executables
10
+ cert_chain: []
11
+ date: 2020-01-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: " "
14
+ email: opensource@eventide-project.org
15
+ executables:
16
+ - pg-stats-table-indexes-size
17
+ - pg-stats-total-index-size
18
+ - pg-stats-records-rank
19
+ - pg-stats-locks
20
+ - pg-stats-index-usage
21
+ - pg-stats-seq-scans
22
+ - pg-stats-total-table-size
23
+ - pg-stats-bloat
24
+ - pg-stats-index-size
25
+ - pg-stats-blocking-queries
26
+ - pg-stats-unused-indexes
27
+ - pg-stats-long-running-queries
28
+ - pg-stats-extensions
29
+ - pg-stats-statements-reset
30
+ - pg-stats-outliers
31
+ - pg-stats-vacuum
32
+ - pg-stats-table-size
33
+ - pg-stats-slow-statements
34
+ - pg-stats-cache-hit-rate
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - executables/pg-stats-bloat
39
+ - executables/pg-stats-blocking-queries
40
+ - executables/pg-stats-cache-hit-rate
41
+ - executables/pg-stats-extensions
42
+ - executables/pg-stats-index-size
43
+ - executables/pg-stats-index-usage
44
+ - executables/pg-stats-locks
45
+ - executables/pg-stats-long-running-queries
46
+ - executables/pg-stats-outliers
47
+ - executables/pg-stats-records-rank
48
+ - executables/pg-stats-seq-scans
49
+ - executables/pg-stats-slow-statements
50
+ - executables/pg-stats-statements-reset
51
+ - executables/pg-stats-table-indexes-size
52
+ - executables/pg-stats-table-size
53
+ - executables/pg-stats-total-index-size
54
+ - executables/pg-stats-total-table-size
55
+ - executables/pg-stats-unused-indexes
56
+ - executables/pg-stats-vacuum
57
+ - queries/MIT-License.txt
58
+ - queries/bloat.sql
59
+ - queries/blocking-queries.sql
60
+ - queries/cache-hit-rate.sql
61
+ - queries/extensions.sql
62
+ - queries/index-size.sql
63
+ - queries/index-usage.sql
64
+ - queries/locks.sql
65
+ - queries/long-running-queries.sql
66
+ - queries/outliers.sql
67
+ - queries/records-rank.sql
68
+ - queries/seq-scans.sql
69
+ - queries/slow-statements.sql
70
+ - queries/table-indexes-size.sql
71
+ - queries/table-size.sql
72
+ - queries/total-index-size.sql
73
+ - queries/total-table-size.sql
74
+ - queries/unused-indexes.sql
75
+ - queries/vacuum.sql
76
+ - scripts/bloat.sh
77
+ - scripts/blocking-queries.sh
78
+ - scripts/cache-hit-rate.sh
79
+ - scripts/extensions.sh
80
+ - scripts/index-size.sh
81
+ - scripts/index-usage.sh
82
+ - scripts/locks.sh
83
+ - scripts/long-running-queries.sh
84
+ - scripts/outliers.sh
85
+ - scripts/records-rank.sh
86
+ - scripts/run.sh
87
+ - scripts/seq-scans.sh
88
+ - scripts/slow-statements.sh
89
+ - scripts/statements-reset.sh
90
+ - scripts/table-indexes-size.sh
91
+ - scripts/table-size.sh
92
+ - scripts/total-index-size.sh
93
+ - scripts/total-table-size.sh
94
+ - scripts/unused-indexes.sh
95
+ - scripts/vacuum.sh
96
+ homepage: https://github.com/pg-stats/pg-stats
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.0.1
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Database Statistics for Postgres
119
+ test_files: []