ruby-pg-extras 1.3.0 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d6fbc5ab6b75d6afab360ce585c6b99da6f7c7622da5c7d41ef5c9a352cf1d0
4
- data.tar.gz: d6065e2b079138d523ea47dd5855793e6c53d45d7d0f59f6035a3f0cc22e97d1
3
+ metadata.gz: 5536e950d12ba0a63deee72240de7d657f7cf33e8c5bb93622a5a29c6ba4898f
4
+ data.tar.gz: 8fa1ecf9537e4d4b8774e5fbbd37e7f329dd3d31a37ad83a93a7c1b5ad4fa9c4
5
5
  SHA512:
6
- metadata.gz: 06235baa16b1433f94c6df83cdd764792ab85217ea0dae0880fedf981f84e7e4a12748e267462bc99a69096dd7706cf6893680d24f7b1e7da5fc8c502e4bc9fb
7
- data.tar.gz: 0cce03aa9d5e05cc826c4d4835fc4fc8c3d50f3d062dfbdd7deec85d4b51366de68e264d3e3023f509464144ab80ae983975cecb50aaf3d333b1a8e0962df878
6
+ metadata.gz: 836b17e1988508f27adcd8138f3d5d5c070e93bbb7ce28ad9e8f254582092798225d3cc96d5dce827662d9fcd98e82cbf08d5ea789cb2c3d65614f9865a7d134
7
+ data.tar.gz: de4d8f3511a66e1d636fa47fcccf828ad3bb9a6a3e0bb0f26fcf120674c7381b0422c94a210e102b78f4b1f82e56299762bfff85916dd0ee7b5800dfac10bc8d
data/README.md CHANGED
@@ -85,6 +85,13 @@ RubyPGExtras.cache_hit(in_format: :raw) =>
85
85
  #<PG::Result:0x00007f75777f7328 status=PGRES_TUPLES_OK ntuples=2 nfields=2 cmd_tuples=2>
86
86
  ```
87
87
 
88
+ Some methods accept an optional `args` param allowing you to customize queries:
89
+
90
+ ```ruby
91
+ RubyPGExtras.long_running_queries(args: { threshold: "200 milliseconds" })
92
+
93
+ ```
94
+
88
95
  ## Available methods
89
96
 
90
97
  ### `cache_hit`
@@ -185,7 +192,7 @@ This command displays all the current locks, regardless of their type.
185
192
 
186
193
  ```ruby
187
194
 
188
- RubyPGExtras.outliers
195
+ RubyPGExtras.outliers(args: { limit: 20 })
189
196
 
190
197
  qry | exec_time | prop_exec_time | ncalls | sync_io_time
191
198
  -----------------------------------------+------------------+----------------+-------------+--------------
@@ -207,7 +214,7 @@ Typically, an efficient query will have an appropriate ratio of calls to total e
207
214
 
208
215
  ```ruby
209
216
 
210
- RubyPGExtras.calls
217
+ RubyPGExtras.calls(args: { limit: 10 })
211
218
 
212
219
  qry | exec_time | prop_exec_time | ncalls | sync_io_time
213
220
  -----------------------------------------+------------------+----------------+-------------+--------------
@@ -332,7 +339,7 @@ This command displays the total size of each table and materialized view in the
332
339
 
333
340
  ```ruby
334
341
 
335
- RubyPGExtras.unused_indexes
342
+ RubyPGExtras.unused_indexes(args: { min_scans: 20 })
336
343
 
337
344
  table | index | index_size | index_scans
338
345
  ---------------------+--------------------------------------------+------------+-------------
@@ -344,6 +351,22 @@ RubyPGExtras.unused_indexes
344
351
 
345
352
  This command displays indexes that have < 50 scans recorded against them, and are greater than 5 pages in size, ordered by size relative to the number of index scans. This command is generally useful for eliminating indexes that are unused, which can impact write performance, as well as read performance should they occupy space in memory.
346
353
 
354
+ ### `null_indexes`
355
+
356
+ ```ruby
357
+
358
+ RubyPGExtras.null_indexes(args: { min_relation_size_mb: 10 })
359
+
360
+ oid | index | index_size | unique | indexed_column | null_frac | expected_saving
361
+ ---------+--------------------+------------+--------+----------------+-----------+-----------------
362
+ 183764 | users_reset_token | 1445 MB | t | reset_token | 97.00% | 1401 MB
363
+ 88732 | plan_cancelled_at | 539 MB | f | cancelled_at | 8.30% | 44 MB
364
+ 9827345 | users_email | 18 MB | t | email | 28.67% | 5160 kB
365
+
366
+ ```
367
+
368
+ This commands displays indexes that contain `NULL` values. A high ratio of `NULL` values means that using a partial index excluding them will be beneficial in case they are not used for searching. [Source and more info](https://hakibenita.com/postgresql-unused-index-size).
369
+
347
370
  ### `seq_scans`
348
371
 
349
372
  ```ruby
@@ -370,7 +393,7 @@ This command displays the number of sequential scans recorded against all tables
370
393
 
371
394
  ```ruby
372
395
 
373
- RubyPGExtras.long_running_queries
396
+ RubyPGExtras.long_running_queries(args: { threshold: "200 milliseconds" })
374
397
 
375
398
 
376
399
  pid | duration | query
@@ -10,7 +10,7 @@ module RubyPGExtras
10
10
  QUERIES = %i(
11
11
  bloat blocking cache_hit
12
12
  calls extensions table_cache_hit index_cache_hit
13
- index_size index_usage locks all_locks
13
+ index_size index_usage null_indexes locks all_locks
14
14
  long_running_queries mandelbrot outliers
15
15
  records_rank seq_scans table_indexes_size
16
16
  table_size total_index_size total_table_size
@@ -19,9 +19,10 @@ module RubyPGExtras
19
19
 
20
20
  DEFAULT_ARGS = Hash.new({}).merge({
21
21
  calls: { limit: 10 },
22
- long_running_queries: { interval: '5 seconds' },
22
+ long_running_queries: { threshold: "500 milliseconds" },
23
23
  outliers: { limit: 10 },
24
- unused_indexes: { min_scans: 50 }
24
+ unused_indexes: { min_scans: 50 },
25
+ null_indexes: { min_relation_size_mb: 10 }
25
26
  })
26
27
 
27
28
  QUERIES.each do |query_name|
@@ -1,4 +1,4 @@
1
- /* All queries longer than five minutes by descending duration */
1
+ /* All queries longer than the threshold by descending duration */
2
2
 
3
3
  SELECT
4
4
  pid,
@@ -9,6 +9,6 @@ FROM
9
9
  WHERE
10
10
  pg_stat_activity.query <> ''::text
11
11
  AND state <> 'idle'
12
- AND now() - pg_stat_activity.query_start > interval '%{interval}'
12
+ AND now() - pg_stat_activity.query_start > interval '%{threshold}'
13
13
  ORDER BY
14
14
  now() - pg_stat_activity.query_start DESC;
@@ -0,0 +1,33 @@
1
+ /* Find indexes with a high ratio of NULL values */
2
+
3
+ SELECT
4
+ c.oid,
5
+ c.relname AS index,
6
+ pg_size_pretty(pg_relation_size(c.oid)) AS index_size,
7
+ i.indisunique AS unique,
8
+ a.attname AS indexed_column,
9
+ CASE s.null_frac
10
+ WHEN 0 THEN ''
11
+ ELSE to_char(s.null_frac * 100, '999.00%%')
12
+ END AS null_frac,
13
+ pg_size_pretty((pg_relation_size(c.oid) * s.null_frac)::bigint) AS expected_saving
14
+ FROM
15
+ pg_class c
16
+ JOIN pg_index i ON i.indexrelid = c.oid
17
+ JOIN pg_attribute a ON a.attrelid = c.oid
18
+ JOIN pg_class c_table ON c_table.oid = i.indrelid
19
+ JOIN pg_indexes ixs ON c.relname = ixs.indexname
20
+ LEFT JOIN pg_stats s ON s.tablename = c_table.relname AND a.attname = s.attname
21
+ WHERE
22
+ -- Primary key cannot be partial
23
+ NOT i.indisprimary
24
+ -- Exclude already partial indexes
25
+ AND i.indpred IS NULL
26
+ -- Exclude composite indexes
27
+ AND array_length(i.indkey, 1) = 1
28
+ -- Exclude indexes without null_frac ratio
29
+ AND coalesce(s.null_frac, 0) != 0
30
+ -- Larger than threshold
31
+ AND pg_relation_size(c.oid) > %{min_relation_size_mb} * 1024 ^ 2
32
+ ORDER BY
33
+ pg_relation_size(c.oid) * s.null_frac DESC;
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyPGExtras
4
- VERSION = "1.3.0"
4
+ VERSION = "1.5.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-pg-extras
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -96,6 +96,7 @@ files:
96
96
  - lib/ruby-pg-extras/queries/locks.sql
97
97
  - lib/ruby-pg-extras/queries/long_running_queries.sql
98
98
  - lib/ruby-pg-extras/queries/mandelbrot.sql
99
+ - lib/ruby-pg-extras/queries/null_indexes.sql
99
100
  - lib/ruby-pg-extras/queries/outliers.sql
100
101
  - lib/ruby-pg-extras/queries/records_rank.sql
101
102
  - lib/ruby-pg-extras/queries/seq_scans.sql