pg-stats 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []