ruby-pg-extras 1.3.1 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +67 -4
- data/lib/ruby-pg-extras.rb +5 -4
- data/lib/ruby-pg-extras/queries/db_settings.sql +9 -0
- data/lib/ruby-pg-extras/queries/long_running_queries.sql +1 -1
- data/lib/ruby-pg-extras/queries/null_indexes.sql +33 -0
- data/lib/ruby-pg-extras/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3de471f9f4d008d006000667b4b52d4e0d8aec0c5dc9ef55ce6045e5e8f96994
|
4
|
+
data.tar.gz: bb78196a09f0af1d7f4be623f1794223b3db074d19eb439e59670b8e960d06e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ed2d3f75a540b6e8b22db825a1479a53649ee3ddde59ca7783301f5e42d89f8a8c1d40e11b42a5f1340f3b72d866531a6878c57ccfb211f43ca00d21d82c177
|
7
|
+
data.tar.gz: 5f6618ededb729f9d085cfdc5c5c722065ccd8beee6cb191bdfc3e6e58700fa2468d0f5aa3f7829fc9d520d7fb66fe248d897d989fe7fec9c21896cb2234bdad
|
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`
|
@@ -102,6 +109,8 @@ RubyPGExtras.cache_hit
|
|
102
109
|
|
103
110
|
This command provides information on the efficiency of the buffer cache, for both index reads (`index hit rate`) as well as table reads (`table hit rate`). A low buffer cache hit ratio can be a sign that the Postgres instance is too small for the workload.
|
104
111
|
|
112
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#cache-hit)
|
113
|
+
|
105
114
|
### `index_cache_hit`
|
106
115
|
|
107
116
|
```ruby
|
@@ -118,6 +127,8 @@ RubyPGExtras.index_cache_hit
|
|
118
127
|
|
119
128
|
The same as `cache_hit` with each table's indexes cache hit info displayed separately.
|
120
129
|
|
130
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#cache-hit)
|
131
|
+
|
121
132
|
### `table_cache_hit`
|
122
133
|
|
123
134
|
```ruby
|
@@ -134,6 +145,26 @@ RubyPGExtras.table_cache_hit
|
|
134
145
|
|
135
146
|
The same as `cache_hit` with each table's cache hit info displayed seperately.
|
136
147
|
|
148
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#cache-hit)
|
149
|
+
|
150
|
+
### `db_settings`
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
|
154
|
+
RubyPGExtras.db_settings
|
155
|
+
|
156
|
+
name | setting | unit |
|
157
|
+
------------------------------+---------+------+
|
158
|
+
checkpoint_completion_target | 0.7 | |
|
159
|
+
default_statistics_target | 100 | |
|
160
|
+
effective_cache_size | 1350000 | 8kB |
|
161
|
+
effective_io_concurrency | 1 | |
|
162
|
+
(truncated results for brevity)
|
163
|
+
|
164
|
+
```
|
165
|
+
|
166
|
+
This method displays values for selected PostgreSQL settings. You can compare them with settings recommended by [PGTune](https://pgtune.leopard.in.ua/#/) and tweak values to improve performance.
|
167
|
+
|
137
168
|
### `index_usage`
|
138
169
|
|
139
170
|
```ruby
|
@@ -171,6 +202,8 @@ RubyPGExtras.locks
|
|
171
202
|
|
172
203
|
This command displays queries that have taken out an exclusive lock on a relation. Exclusive locks typically prevent other operations on that relation from taking place, and can be a cause of "hung" queries that are waiting for a lock to be granted.
|
173
204
|
|
205
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#deadlocks)
|
206
|
+
|
174
207
|
### `all_locks`
|
175
208
|
|
176
209
|
```ruby
|
@@ -185,7 +218,7 @@ This command displays all the current locks, regardless of their type.
|
|
185
218
|
|
186
219
|
```ruby
|
187
220
|
|
188
|
-
RubyPGExtras.outliers
|
221
|
+
RubyPGExtras.outliers(args: { limit: 20 })
|
189
222
|
|
190
223
|
qry | exec_time | prop_exec_time | ncalls | sync_io_time
|
191
224
|
-----------------------------------------+------------------+----------------+-------------+--------------
|
@@ -203,11 +236,13 @@ This command displays statements, obtained from `pg_stat_statements`, ordered by
|
|
203
236
|
|
204
237
|
Typically, an efficient query will have an appropriate ratio of calls to total execution time, with as little time spent on I/O as possible. Queries that have a high total execution time but low call count should be investigated to improve their performance. Queries that have a high proportion of execution time being spent on synchronous I/O should also be investigated.
|
205
238
|
|
239
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#missing-indexes)
|
240
|
+
|
206
241
|
### `calls`
|
207
242
|
|
208
243
|
```ruby
|
209
244
|
|
210
|
-
RubyPGExtras.calls
|
245
|
+
RubyPGExtras.calls(args: { limit: 10 })
|
211
246
|
|
212
247
|
qry | exec_time | prop_exec_time | ncalls | sync_io_time
|
213
248
|
-----------------------------------------+------------------+----------------+-------------+--------------
|
@@ -223,6 +258,8 @@ RubyPGExtras.calls
|
|
223
258
|
|
224
259
|
This command is much like `pg:outliers`, but ordered by the number of times a statement has been called.
|
225
260
|
|
261
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#missing-indexes)
|
262
|
+
|
226
263
|
### `blocking`
|
227
264
|
|
228
265
|
```ruby
|
@@ -237,6 +274,8 @@ RubyPGExtras.blocking
|
|
237
274
|
|
238
275
|
This command displays statements that are currently holding locks that other statements are waiting to be released. This can be used in conjunction with `pg:locks` to determine which statements need to be terminated in order to resolve lock contention.
|
239
276
|
|
277
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#deadlocks)
|
278
|
+
|
240
279
|
### `total_index_size`
|
241
280
|
|
242
281
|
```ruby
|
@@ -332,7 +371,7 @@ This command displays the total size of each table and materialized view in the
|
|
332
371
|
|
333
372
|
```ruby
|
334
373
|
|
335
|
-
RubyPGExtras.unused_indexes
|
374
|
+
RubyPGExtras.unused_indexes(args: { min_scans: 20 })
|
336
375
|
|
337
376
|
table | index | index_size | index_scans
|
338
377
|
---------------------+--------------------------------------------+------------+-------------
|
@@ -344,6 +383,26 @@ RubyPGExtras.unused_indexes
|
|
344
383
|
|
345
384
|
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
385
|
|
386
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#unused-indexes)
|
387
|
+
|
388
|
+
### `null_indexes`
|
389
|
+
|
390
|
+
```ruby
|
391
|
+
|
392
|
+
RubyPGExtras.null_indexes(args: { min_relation_size_mb: 10 })
|
393
|
+
|
394
|
+
oid | index | index_size | unique | indexed_column | null_frac | expected_saving
|
395
|
+
---------+--------------------+------------+--------+----------------+-----------+-----------------
|
396
|
+
183764 | users_reset_token | 1445 MB | t | reset_token | 97.00% | 1401 MB
|
397
|
+
88732 | plan_cancelled_at | 539 MB | f | cancelled_at | 8.30% | 44 MB
|
398
|
+
9827345 | users_email | 18 MB | t | email | 28.67% | 5160 kB
|
399
|
+
|
400
|
+
```
|
401
|
+
|
402
|
+
This command 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.
|
403
|
+
|
404
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#null-indexes)
|
405
|
+
|
347
406
|
### `seq_scans`
|
348
407
|
|
349
408
|
```ruby
|
@@ -366,11 +425,13 @@ RubyPGExtras.seq_scans
|
|
366
425
|
|
367
426
|
This command displays the number of sequential scans recorded against all tables, descending by count of sequential scans. Tables that have very high numbers of sequential scans may be under-indexed, and it may be worth investigating queries that read from these tables.
|
368
427
|
|
428
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#missing-indexes)
|
429
|
+
|
369
430
|
### `long_running_queries`
|
370
431
|
|
371
432
|
```ruby
|
372
433
|
|
373
|
-
RubyPGExtras.long_running_queries
|
434
|
+
RubyPGExtras.long_running_queries(args: { threshold: "200 milliseconds" })
|
374
435
|
|
375
436
|
|
376
437
|
pid | duration | query
|
@@ -421,6 +482,8 @@ RubyPGExtras.bloat
|
|
421
482
|
|
422
483
|
This command displays an estimation of table "bloat" – space allocated to a relation that is full of dead tuples, that has yet to be reclaimed. Tables that have a high bloat ratio, typically 10 or greater, should be investigated to see if vacuuming is aggressive enough, and can be a sign of high table churn.
|
423
484
|
|
485
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#bloat)
|
486
|
+
|
424
487
|
### `vacuum_stats`
|
425
488
|
|
426
489
|
```ruby
|
data/lib/ruby-pg-extras.rb
CHANGED
@@ -8,9 +8,9 @@ module RubyPGExtras
|
|
8
8
|
@@database_url = nil
|
9
9
|
|
10
10
|
QUERIES = %i(
|
11
|
-
bloat blocking cache_hit
|
11
|
+
bloat blocking cache_hit db_settings
|
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|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/* Values of selected PostgreSQL settings */
|
2
|
+
|
3
|
+
SELECT name, setting, unit, short_desc FROM pg_settings
|
4
|
+
WHERE name IN (
|
5
|
+
'max_connections', 'shared_buffers', 'effective_cache_size',
|
6
|
+
'maintenance_work_mem', 'checkpoint_completion_target', 'wal_buffers',
|
7
|
+
'default_statistics_target', 'random_page_cost', 'effective_io_concurrency',
|
8
|
+
'work_mem', 'min_wal_size', 'max_wal_size'
|
9
|
+
);
|
@@ -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.3
|
4
|
+
version: 1.5.3
|
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-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- lib/ruby-pg-extras/queries/blocking.sql
|
89
89
|
- lib/ruby-pg-extras/queries/cache_hit.sql
|
90
90
|
- lib/ruby-pg-extras/queries/calls.sql
|
91
|
+
- lib/ruby-pg-extras/queries/db_settings.sql
|
91
92
|
- lib/ruby-pg-extras/queries/extensions.sql
|
92
93
|
- lib/ruby-pg-extras/queries/index_cache_hit.sql
|
93
94
|
- lib/ruby-pg-extras/queries/index_size.sql
|
@@ -96,6 +97,7 @@ files:
|
|
96
97
|
- lib/ruby-pg-extras/queries/locks.sql
|
97
98
|
- lib/ruby-pg-extras/queries/long_running_queries.sql
|
98
99
|
- lib/ruby-pg-extras/queries/mandelbrot.sql
|
100
|
+
- lib/ruby-pg-extras/queries/null_indexes.sql
|
99
101
|
- lib/ruby-pg-extras/queries/outliers.sql
|
100
102
|
- lib/ruby-pg-extras/queries/records_rank.sql
|
101
103
|
- lib/ruby-pg-extras/queries/seq_scans.sql
|