ruby-pg-extras 1.5.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +32 -5
- data/README.md +60 -0
- data/Rakefile +4 -0
- data/docker-compose.yml.sample +20 -1
- data/lib/ruby-pg-extras/queries/buffercache_stats.sql +13 -0
- data/lib/ruby-pg-extras/queries/buffercache_usage.sql +9 -0
- data/lib/ruby-pg-extras/queries/calls.sql +2 -2
- data/lib/ruby-pg-extras/queries/calls_legacy.sql +9 -0
- data/lib/ruby-pg-extras/queries/duplicate_indexes.sql +11 -0
- data/lib/ruby-pg-extras/queries/outliers.sql +3 -3
- data/lib/ruby-pg-extras/queries/outliers_legacy.sql +10 -0
- data/lib/ruby-pg-extras/queries/ssl_used.sql +4 -0
- data/lib/ruby-pg-extras/version.rb +1 -1
- data/lib/ruby-pg-extras.rb +17 -1
- data/spec/smoke_spec.rb +6 -3
- data/spec/spec_helper.rb +13 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67ee92c7a3fefa174bf843ee90a6d0247968726dbddfa57d83e02bec80614b3c
|
4
|
+
data.tar.gz: '0893af856168f741cfe505c39415211b079202684e4472f38614f76bc6bfc7e2'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b63de82209cb9b52710c29360025058e88987ec14d48c5d59ab16f677512fab8d11f7042cd168358971b30421edf0910d59a69d082dc024440991cac5820ddf7
|
7
|
+
data.tar.gz: 4c9bd4431a96091ba6e5ba581ae7b7493a3b49d5329e0cd85903f90dbc13477e2d519a719ff078117b9e03a0b7dc89efb263eaafc3e458a4ff5ff6beb5e6fe23
|
data/.circleci/config.yml
CHANGED
@@ -6,6 +6,22 @@ jobs:
|
|
6
6
|
environment:
|
7
7
|
DATABASE_URL: postgresql://postgres:secret@localhost:5432/ruby-pg-extras-test
|
8
8
|
- image: circleci/postgres:11.5
|
9
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
10
|
+
name: postgres11
|
11
|
+
environment:
|
12
|
+
POSTGRES_USER: postgres
|
13
|
+
POSTGRES_DB: ruby-pg-extras-test
|
14
|
+
POSTGRES_PASSWORD: secret
|
15
|
+
- image: circleci/postgres:12.7
|
16
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
17
|
+
name: postgres12
|
18
|
+
environment:
|
19
|
+
POSTGRES_USER: postgres
|
20
|
+
POSTGRES_DB: ruby-pg-extras-test
|
21
|
+
POSTGRES_PASSWORD: secret
|
22
|
+
- image: circleci/postgres:13.3
|
23
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
24
|
+
name: postgres13
|
9
25
|
environment:
|
10
26
|
POSTGRES_USER: postgres
|
11
27
|
POSTGRES_DB: ruby-pg-extras-test
|
@@ -16,13 +32,24 @@ jobs:
|
|
16
32
|
- run: gem update --system
|
17
33
|
- run: gem install bundler
|
18
34
|
- run: bundle install --path vendor/bundle
|
19
|
-
- run: sudo apt-get update
|
35
|
+
- run: sudo apt-get update --allow-releaseinfo-change
|
20
36
|
- run: sudo apt install postgresql-client-11
|
21
|
-
- run: dockerize -wait tcp://
|
37
|
+
- run: dockerize -wait tcp://postgres11:5432 -timeout 1m
|
38
|
+
- run:
|
39
|
+
name: Run specs for PG 11
|
40
|
+
environment:
|
41
|
+
DATABASE_URL: postgresql://postgres:secret@postgres11:5432/ruby-pg-extras-test
|
42
|
+
command: bundle exec rspec spec/
|
43
|
+
- run:
|
44
|
+
name: Run specs for PG 12
|
45
|
+
environment:
|
46
|
+
DATABASE_URL: postgresql://postgres:secret@postgres12:5432/ruby-pg-extras-test
|
47
|
+
command: bundle exec rspec spec/
|
22
48
|
- run:
|
23
|
-
name: Run specs
|
24
|
-
|
25
|
-
|
49
|
+
name: Run specs for PG 13
|
50
|
+
environment:
|
51
|
+
DATABASE_URL: postgresql://postgres:secret@postgres13:5432/ruby-pg-extras-test
|
52
|
+
command: bundle exec rspec spec/
|
26
53
|
workflows:
|
27
54
|
version: 2
|
28
55
|
test:
|
data/README.md
CHANGED
@@ -165,6 +165,22 @@ RubyPGExtras.db_settings
|
|
165
165
|
|
166
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
167
|
|
168
|
+
[More info](https://pawelurbanek.com/postgresql-fix-performance#cache-hit)
|
169
|
+
|
170
|
+
### 'ssl_used'
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
|
174
|
+
RubyPGExtras.ssl_used
|
175
|
+
|
176
|
+
| ssl_is_used |
|
177
|
+
+---------------------------------+
|
178
|
+
| t |
|
179
|
+
|
180
|
+
```
|
181
|
+
|
182
|
+
Returns boolean indicating if an encrypted SSL is currently used. Connecting to the database via an unencrypted connection is a critical security risk.
|
183
|
+
|
168
184
|
### `index_usage`
|
169
185
|
|
170
186
|
```ruby
|
@@ -385,6 +401,19 @@ This command displays indexes that have < 50 scans recorded against them, and ar
|
|
385
401
|
|
386
402
|
[More info](https://pawelurbanek.com/postgresql-fix-performance#unused-indexes)
|
387
403
|
|
404
|
+
### `duplicate_indexes`
|
405
|
+
|
406
|
+
```ruby
|
407
|
+
|
408
|
+
RubyPGExtras.duplicate_indexes
|
409
|
+
|
410
|
+
| size | idx1 | idx2 | idx3 | idx4 |
|
411
|
+
+------------+--------------+----------------+----------+-----------+
|
412
|
+
| 128 k | users_pkey | index_users_id | | |
|
413
|
+
```
|
414
|
+
|
415
|
+
This command displays multiple indexes that have the same set of columns, same opclass, expression and predicate - which make them equivalent. Usually it's safe to drop one of them.
|
416
|
+
|
388
417
|
### `null_indexes`
|
389
418
|
|
390
419
|
```ruby
|
@@ -512,6 +541,22 @@ RubyPGExtras.kill_all
|
|
512
541
|
|
513
542
|
This commands kills all the currently active connections to the database. It can be useful as a last resort when your database is stuck in a deadlock.
|
514
543
|
|
544
|
+
### `buffercache_stats`
|
545
|
+
|
546
|
+
```ruby
|
547
|
+
RubyPGExtras.buffercache_stats(args: { limit: 10 })
|
548
|
+
```
|
549
|
+
|
550
|
+
This command shows the relations buffered in database share buffer, ordered by percentage taken. It also shows that how much of the whole relation is buffered.
|
551
|
+
|
552
|
+
### `buffercache_usage`
|
553
|
+
|
554
|
+
```ruby
|
555
|
+
RubyPGExtras.buffercache_usage(args: { limit: 20 })
|
556
|
+
```
|
557
|
+
|
558
|
+
This command calculates how many blocks from which table are currently cached.
|
559
|
+
|
515
560
|
### `extensions`
|
516
561
|
|
517
562
|
```ruby
|
@@ -531,3 +576,18 @@ RubyPGExtras.mandelbrot
|
|
531
576
|
```
|
532
577
|
|
533
578
|
This command outputs the Mandelbrot set, calculated through SQL.
|
579
|
+
|
580
|
+
## Testing
|
581
|
+
|
582
|
+
```bash
|
583
|
+
cp docker-compose.yml.sample docker-compose.yml
|
584
|
+
docker compose up -d
|
585
|
+
rake test_all
|
586
|
+
```
|
587
|
+
|
588
|
+
## Query sources
|
589
|
+
|
590
|
+
- [https://github.com/heroku/heroku-pg-extras](https://github.com/heroku/heroku-pg-extras)
|
591
|
+
- [https://hakibenita.com/postgresql-unused-index-size](https://hakibenita.com/postgresql-unused-index-size)
|
592
|
+
- [https://sites.google.com/site/itmyshare/database-tips-and-examples/postgres/useful-sqls-to-check-contents-of-postgresql-shared_buffer](https://sites.google.com/site/itmyshare/database-tips-and-examples/postgres/useful-sqls-to-check-contents-of-postgresql-shared_buffer)
|
593
|
+
- [https://wiki.postgresql.org/wiki/Index_Maintenance](https://wiki.postgresql.org/wiki/Index_Maintenance)
|
data/Rakefile
CHANGED
data/docker-compose.yml.sample
CHANGED
@@ -1,11 +1,30 @@
|
|
1
1
|
version: '3'
|
2
2
|
|
3
3
|
services:
|
4
|
-
|
4
|
+
postgres11:
|
5
5
|
image: postgres:11.5-alpine
|
6
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
6
7
|
environment:
|
7
8
|
POSTGRES_USER: postgres
|
8
9
|
POSTGRES_DB: ruby-pg-extras-test
|
9
10
|
POSTGRES_PASSWORD: secret
|
10
11
|
ports:
|
11
12
|
- '5432:5432'
|
13
|
+
postgres12:
|
14
|
+
image: postgres:12.7-alpine
|
15
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
16
|
+
environment:
|
17
|
+
POSTGRES_USER: postgres
|
18
|
+
POSTGRES_DB: ruby-pg-extras-test
|
19
|
+
POSTGRES_PASSWORD: secret
|
20
|
+
ports:
|
21
|
+
- '5433:5432'
|
22
|
+
postgres13:
|
23
|
+
image: postgres:13.3-alpine
|
24
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
25
|
+
environment:
|
26
|
+
POSTGRES_USER: postgres
|
27
|
+
POSTGRES_DB: ruby-pg-extras-test
|
28
|
+
POSTGRES_PASSWORD: secret
|
29
|
+
ports:
|
30
|
+
- '5434:5432'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/* Calculates percentages of relations buffered in database share buffer */
|
2
|
+
|
3
|
+
SELECT
|
4
|
+
c.relname,
|
5
|
+
pg_size_pretty(count(*) * 8192) AS buffered,
|
6
|
+
round(100.0 * count(*) / (SELECT setting FROM pg_settings WHERE name = 'shared_buffers')::integer, 1) AS buffer_percent,
|
7
|
+
round(100.0 * count(*) * 8192 / pg_table_size(c.oid), 1) AS percent_of_relation
|
8
|
+
FROM pg_class c
|
9
|
+
INNER JOIN pg_buffercache b ON b.relfilenode = c.relfilenode
|
10
|
+
INNER JOIN pg_database d ON (b.reldatabase = d.oid AND d.datname = current_database())
|
11
|
+
GROUP BY c.oid,c.relname
|
12
|
+
ORDER BY 3 DESC
|
13
|
+
LIMIT %{limit};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/* Calculate how many blocks from which table are currently cached */
|
2
|
+
|
3
|
+
SELECT c.relname, count(*) AS buffers
|
4
|
+
FROM pg_class c
|
5
|
+
INNER JOIN pg_buffercache b ON b.relfilenode = c.relfilenode
|
6
|
+
INNER JOIN pg_database d ON (b.reldatabase = d.oid AND d.datname = current_database())
|
7
|
+
GROUP BY c.relname
|
8
|
+
ORDER BY 2 DESC
|
9
|
+
LIMIT %{limit};
|
@@ -1,8 +1,8 @@
|
|
1
1
|
/* Queries that have highest frequency of execution */
|
2
2
|
|
3
3
|
SELECT query AS qry,
|
4
|
-
interval '1 millisecond' *
|
5
|
-
to_char((
|
4
|
+
interval '1 millisecond' * total_exec_time AS exec_time,
|
5
|
+
to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%%' AS prop_exec_time,
|
6
6
|
to_char(calls, 'FM999G999G990') AS ncalls,
|
7
7
|
interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time
|
8
8
|
FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/* Queries that have highest frequency of execution */
|
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 %{limit};
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/* Multiple indexes that have the same set of columns, same opclass, expression and predicate. */
|
2
|
+
|
3
|
+
SELECT pg_size_pretty(sum(pg_relation_size(idx))::bigint) as size,
|
4
|
+
(array_agg(idx))[1] as idx1, (array_agg(idx))[2] as idx2,
|
5
|
+
(array_agg(idx))[3] as idx3, (array_agg(idx))[4] as idx4
|
6
|
+
FROM (
|
7
|
+
SELECT indexrelid::regclass as idx, (indrelid::text ||E'\n'|| indclass::text ||E'\n'|| indkey::text ||E'\n'||
|
8
|
+
coalesce(indexprs::text,'')||E'\n' || coalesce(indpred::text,'')) as key
|
9
|
+
FROM pg_index) sub
|
10
|
+
GROUP BY key HAVING count(*)>1
|
11
|
+
ORDER BY sum(pg_relation_size(idx)) DESC;
|
@@ -1,10 +1,10 @@
|
|
1
1
|
/* Queries that have longest execution time in aggregate */
|
2
2
|
|
3
|
-
SELECT interval '1 millisecond' *
|
4
|
-
to_char((
|
3
|
+
SELECT interval '1 millisecond' * total_exec_time AS total_exec_time,
|
4
|
+
to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%%' AS prop_exec_time,
|
5
5
|
to_char(calls, 'FM999G999G999G990') AS ncalls,
|
6
6
|
interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time,
|
7
7
|
query AS query
|
8
8
|
FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
|
9
|
-
ORDER BY
|
9
|
+
ORDER BY total_exec_time DESC
|
10
10
|
LIMIT %{limit};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/* 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 %{limit};
|
data/lib/ruby-pg-extras.rb
CHANGED
@@ -6,6 +6,7 @@ require 'pg'
|
|
6
6
|
|
7
7
|
module RubyPGExtras
|
8
8
|
@@database_url = nil
|
9
|
+
NEW_PG_STAT_STATEMENTS = "1.8"
|
9
10
|
|
10
11
|
QUERIES = %i(
|
11
12
|
bloat blocking cache_hit db_settings
|
@@ -14,13 +15,18 @@ module RubyPGExtras
|
|
14
15
|
long_running_queries mandelbrot outliers
|
15
16
|
records_rank seq_scans table_indexes_size
|
16
17
|
table_size total_index_size total_table_size
|
17
|
-
unused_indexes vacuum_stats kill_all
|
18
|
+
unused_indexes duplicate_indexes vacuum_stats kill_all
|
19
|
+
buffercache_stats buffercache_usage ssl_used
|
18
20
|
)
|
19
21
|
|
20
22
|
DEFAULT_ARGS = Hash.new({}).merge({
|
21
23
|
calls: { limit: 10 },
|
24
|
+
calls_legacy: { limit: 10 },
|
22
25
|
long_running_queries: { threshold: "500 milliseconds" },
|
23
26
|
outliers: { limit: 10 },
|
27
|
+
outliers_legacy: { limit: 10 },
|
28
|
+
buffercache_stats: { limit: 10 },
|
29
|
+
buffercache_usage: { limit: 20 },
|
24
30
|
unused_indexes: { min_scans: 50 },
|
25
31
|
null_indexes: { min_relation_size_mb: 10 }
|
26
32
|
})
|
@@ -36,6 +42,16 @@ module RubyPGExtras
|
|
36
42
|
end
|
37
43
|
|
38
44
|
def self.run_query(query_name:, in_format:, args: {})
|
45
|
+
if %i(calls outliers).include?(query_name)
|
46
|
+
pg_stat_statements_ver = RubyPGExtras.connection.exec("select installed_version from pg_available_extensions where name='pg_stat_statements'")
|
47
|
+
.to_a[0].fetch("installed_version", nil)
|
48
|
+
if pg_stat_statements_ver != nil
|
49
|
+
if Gem::Version.new(pg_stat_statements_ver) < Gem::Version.new(NEW_PG_STAT_STATEMENTS)
|
50
|
+
query_name = "#{query_name}_legacy".to_sym
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
39
55
|
sql = if (custom_args = DEFAULT_ARGS[query_name].merge(args)) != {}
|
40
56
|
sql_for(query_name: query_name) % custom_args
|
41
57
|
else
|
data/spec/smoke_spec.rb
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe RubyPGExtras do
|
6
|
+
before(:all) do
|
7
|
+
RubyPGExtras.connection.exec("CREATE EXTENSION IF NOT EXISTS pg_buffercache;")
|
8
|
+
RubyPGExtras.connection.exec("CREATE EXTENSION IF NOT EXISTS pg_stat_statements;")
|
9
|
+
end
|
10
|
+
|
6
11
|
RubyPGExtras::QUERIES.each do |query_name|
|
7
12
|
it "#{query_name} description can be read" do
|
8
13
|
expect do
|
@@ -13,9 +18,7 @@ describe RubyPGExtras do
|
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
(RubyPGExtras::QUERIES - PG_STATS_DEPENDENT_QUERIES).each do |query_name|
|
21
|
+
RubyPGExtras::QUERIES.each do |query_name|
|
19
22
|
it "#{query_name} query can be executed" do
|
20
23
|
expect do
|
21
24
|
RubyPGExtras.run_query(
|
data/spec/spec_helper.rb
CHANGED
@@ -4,4 +4,16 @@ require 'rubygems'
|
|
4
4
|
require 'bundler/setup'
|
5
5
|
require_relative '../lib/ruby-pg-extras'
|
6
6
|
|
7
|
-
ENV["
|
7
|
+
pg_version = ENV["PG_VERSION"]
|
8
|
+
|
9
|
+
port = if pg_version == "11"
|
10
|
+
"5432"
|
11
|
+
elsif pg_version == "12"
|
12
|
+
"5433"
|
13
|
+
elsif pg_version == "13"
|
14
|
+
"5434"
|
15
|
+
else
|
16
|
+
"5432"
|
17
|
+
end
|
18
|
+
|
19
|
+
ENV["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:#{port}/ruby-pg-extras-test"
|
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:
|
4
|
+
version: 2.2.0
|
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-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -86,9 +86,13 @@ files:
|
|
86
86
|
- lib/ruby-pg-extras/queries/all_locks.sql
|
87
87
|
- lib/ruby-pg-extras/queries/bloat.sql
|
88
88
|
- lib/ruby-pg-extras/queries/blocking.sql
|
89
|
+
- lib/ruby-pg-extras/queries/buffercache_stats.sql
|
90
|
+
- lib/ruby-pg-extras/queries/buffercache_usage.sql
|
89
91
|
- lib/ruby-pg-extras/queries/cache_hit.sql
|
90
92
|
- lib/ruby-pg-extras/queries/calls.sql
|
93
|
+
- lib/ruby-pg-extras/queries/calls_legacy.sql
|
91
94
|
- lib/ruby-pg-extras/queries/db_settings.sql
|
95
|
+
- lib/ruby-pg-extras/queries/duplicate_indexes.sql
|
92
96
|
- lib/ruby-pg-extras/queries/extensions.sql
|
93
97
|
- lib/ruby-pg-extras/queries/index_cache_hit.sql
|
94
98
|
- lib/ruby-pg-extras/queries/index_size.sql
|
@@ -99,8 +103,10 @@ files:
|
|
99
103
|
- lib/ruby-pg-extras/queries/mandelbrot.sql
|
100
104
|
- lib/ruby-pg-extras/queries/null_indexes.sql
|
101
105
|
- lib/ruby-pg-extras/queries/outliers.sql
|
106
|
+
- lib/ruby-pg-extras/queries/outliers_legacy.sql
|
102
107
|
- lib/ruby-pg-extras/queries/records_rank.sql
|
103
108
|
- lib/ruby-pg-extras/queries/seq_scans.sql
|
109
|
+
- lib/ruby-pg-extras/queries/ssl_used.sql
|
104
110
|
- lib/ruby-pg-extras/queries/table_cache_hit.sql
|
105
111
|
- lib/ruby-pg-extras/queries/table_indexes_size.sql
|
106
112
|
- lib/ruby-pg-extras/queries/table_size.sql
|
@@ -131,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
137
|
- !ruby/object:Gem::Version
|
132
138
|
version: '0'
|
133
139
|
requirements: []
|
134
|
-
rubygems_version: 3.1.
|
140
|
+
rubygems_version: 3.1.6
|
135
141
|
signing_key:
|
136
142
|
specification_version: 4
|
137
143
|
summary: Ruby PostgreSQL performance database insights
|