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 +4 -4
- data/README.md +27 -4
- data/lib/ruby-pg-extras.rb +4 -3
- data/lib/ruby-pg-extras/queries/long_running_queries.sql +2 -2
- data/lib/ruby-pg-extras/queries/null_indexes.sql +33 -0
- data/lib/ruby-pg-extras/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5536e950d12ba0a63deee72240de7d657f7cf33e8c5bb93622a5a29c6ba4898f
|
4
|
+
data.tar.gz: 8fa1ecf9537e4d4b8774e5fbbd37e7f329dd3d31a37ad83a93a7c1b5ad4fa9c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/ruby-pg-extras.rb
CHANGED
@@ -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: {
|
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
|
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 '%{
|
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;
|
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.
|
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-
|
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
|