ruby-pg-extras 1.6.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 517f1d39dfe5d78d1e8f7650767664b9bc349bf062efb60b421e568afe65be82
4
- data.tar.gz: b60152d78952c4dc8bcee791d445d1aa0028d60bb0af47736095c5b587f605bd
3
+ metadata.gz: a93ebb6cb69e2591e7e9c327b326edf9353105b985f0023ec00deceec631e398
4
+ data.tar.gz: 0e6b50933c072c9c04fba24875d71c0c561ecf4b5a0cb60f8cb66df9cb000075
5
5
  SHA512:
6
- metadata.gz: 8d827609746ab9a203a80c40945ca4b394d9014443d3fb89ae938734d996e3dc3e7f9bce584a7d98297a490365b76e8209e3d43501f932c9c7d39078891f77d4
7
- data.tar.gz: 95dd7b3bb562e194ddac894b9f1e66d05d37d933561333a127ae9dca649c0e2b2259a46b518117b06bcce72729574250b46be935e3f2245eaf9c812ed48346ad
6
+ metadata.gz: b855303347b32b4e20e9a9061f058843f8a337968344d3517a14a70000849691f378e077163720f487c2798df441c1a59f7f53e80b6d45ef2fe7796854cf79f6
7
+ data.tar.gz: 4429a4634e5b154dca182bdb232c64009178f287a00b1c58594dd089221ab2cc1520522ba2112153dd645905685d7751b7c51f9d9a87968d0ab416af93797d26
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://localhost:5432 -timeout 1m
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
- command: |
25
- bundle exec rspec spec/
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
@@ -167,6 +167,20 @@ This method displays values for selected PostgreSQL settings. You can compare th
167
167
 
168
168
  [More info](https://pawelurbanek.com/postgresql-fix-performance#cache-hit)
169
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
+
170
184
  ### `index_usage`
171
185
 
172
186
  ```ruby
@@ -387,6 +401,19 @@ This command displays indexes that have < 50 scans recorded against them, and ar
387
401
 
388
402
  [More info](https://pawelurbanek.com/postgresql-fix-performance#unused-indexes)
389
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
+
390
417
  ### `null_indexes`
391
418
 
392
419
  ```ruby
@@ -514,6 +541,30 @@ RubyPGExtras.kill_all
514
541
 
515
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.
516
543
 
544
+ ### `pg_stat_statements_reset`
545
+
546
+ ```ruby
547
+ RubyPGExtras.pg_stat_statements_reset
548
+ ```
549
+
550
+ This command discards all statistics gathered so far by pg_stat_statements.
551
+
552
+ ### `buffercache_stats`
553
+
554
+ ```ruby
555
+ RubyPGExtras.buffercache_stats(args: { limit: 10 })
556
+ ```
557
+
558
+ 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.
559
+
560
+ ### `buffercache_usage`
561
+
562
+ ```ruby
563
+ RubyPGExtras.buffercache_usage(args: { limit: 20 })
564
+ ```
565
+
566
+ This command calculates how many blocks from which table are currently cached.
567
+
517
568
  ### `extensions`
518
569
 
519
570
  ```ruby
@@ -534,18 +585,17 @@ RubyPGExtras.mandelbrot
534
585
 
535
586
  This command outputs the Mandelbrot set, calculated through SQL.
536
587
 
537
- ### `buffercache_stats`
538
-
539
- 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.
588
+ ## Testing
540
589
 
541
- ```ruby
542
- RubyPGExtras.buffercache_stats(args: { limit: 10 })
590
+ ```bash
591
+ cp docker-compose.yml.sample docker-compose.yml
592
+ docker compose up -d
593
+ rake test_all
543
594
  ```
544
595
 
545
- ### `buffercache_usage`
546
-
547
- This command calculates how many blocks from which table are currently cached.
596
+ ## Query sources
548
597
 
549
- ```ruby
550
- RubyPGExtras.buffercache_usage(args: { limit: 20 })
551
- ```
598
+ - [https://github.com/heroku/heroku-pg-extras](https://github.com/heroku/heroku-pg-extras)
599
+ - [https://hakibenita.com/postgresql-unused-index-size](https://hakibenita.com/postgresql-unused-index-size)
600
+ - [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)
601
+ - [https://wiki.postgresql.org/wiki/Index_Maintenance](https://wiki.postgresql.org/wiki/Index_Maintenance)
data/Rakefile CHANGED
@@ -3,3 +3,7 @@ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
+ desc 'Test all PG versions'
7
+ task :test_all do
8
+ system("PG_VERSION=11 bundle exec rspec spec/ && PG_VERSION=12 bundle exec rspec spec/ && PG_VERSION=13 bundle exec rspec spec/")
9
+ end
@@ -1,11 +1,30 @@
1
1
  version: '3'
2
2
 
3
3
  services:
4
- postgres:
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'
@@ -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' * total_time AS exec_time,
5
- to_char((total_time/sum(total_time) OVER()) * 100, 'FM90D0') || '%%' AS prop_exec_time,
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' * total_time AS total_exec_time,
4
- to_char((total_time/sum(total_time) OVER()) * 100, 'FM90D0') || '%%' AS prop_exec_time,
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 total_time DESC
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};
@@ -0,0 +1,3 @@
1
+ /* pg_stat_statements_reset discards statistics gathered so far by pg_stat_statements */
2
+
3
+ SELECT pg_stat_statements_reset();
@@ -0,0 +1,4 @@
1
+ /* Check if SSL connection is used */
2
+
3
+ CREATE EXTENSION IF NOT EXISTS sslinfo;
4
+ SELECT ssl_is_used();
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyPGExtras
4
- VERSION = "1.6.0"
4
+ VERSION = "2.3.0"
5
5
  end
@@ -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,14 +15,17 @@ 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
- buffercache_stats buffercache_usage
18
+ unused_indexes duplicate_indexes vacuum_stats kill_all
19
+ pg_stat_statements_reset buffercache_stats
20
+ buffercache_usage ssl_used
19
21
  )
20
22
 
21
23
  DEFAULT_ARGS = Hash.new({}).merge({
22
24
  calls: { limit: 10 },
25
+ calls_legacy: { limit: 10 },
23
26
  long_running_queries: { threshold: "500 milliseconds" },
24
27
  outliers: { limit: 10 },
28
+ outliers_legacy: { limit: 10 },
25
29
  buffercache_stats: { limit: 10 },
26
30
  buffercache_usage: { limit: 20 },
27
31
  unused_indexes: { min_scans: 50 },
@@ -39,6 +43,16 @@ module RubyPGExtras
39
43
  end
40
44
 
41
45
  def self.run_query(query_name:, in_format:, args: {})
46
+ if %i(calls outliers).include?(query_name)
47
+ pg_stat_statements_ver = RubyPGExtras.connection.exec("select installed_version from pg_available_extensions where name='pg_stat_statements'")
48
+ .to_a[0].fetch("installed_version", nil)
49
+ if pg_stat_statements_ver != nil
50
+ if Gem::Version.new(pg_stat_statements_ver) < Gem::Version.new(NEW_PG_STAT_STATEMENTS)
51
+ query_name = "#{query_name}_legacy".to_sym
52
+ end
53
+ end
54
+ end
55
+
42
56
  sql = if (custom_args = DEFAULT_ARGS[query_name].merge(args)) != {}
43
57
  sql_for(query_name: query_name) % custom_args
44
58
  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
- PG_STATS_DEPENDENT_QUERIES = %i(calls outliers)
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["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:5432/ruby-pg-extras-test"
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: 1.6.0
4
+ version: 2.3.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-03-29 00:00:00.000000000 Z
11
+ date: 2021-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -90,7 +90,9 @@ files:
90
90
  - lib/ruby-pg-extras/queries/buffercache_usage.sql
91
91
  - lib/ruby-pg-extras/queries/cache_hit.sql
92
92
  - lib/ruby-pg-extras/queries/calls.sql
93
+ - lib/ruby-pg-extras/queries/calls_legacy.sql
93
94
  - lib/ruby-pg-extras/queries/db_settings.sql
95
+ - lib/ruby-pg-extras/queries/duplicate_indexes.sql
94
96
  - lib/ruby-pg-extras/queries/extensions.sql
95
97
  - lib/ruby-pg-extras/queries/index_cache_hit.sql
96
98
  - lib/ruby-pg-extras/queries/index_size.sql
@@ -101,8 +103,11 @@ files:
101
103
  - lib/ruby-pg-extras/queries/mandelbrot.sql
102
104
  - lib/ruby-pg-extras/queries/null_indexes.sql
103
105
  - lib/ruby-pg-extras/queries/outliers.sql
106
+ - lib/ruby-pg-extras/queries/outliers_legacy.sql
107
+ - lib/ruby-pg-extras/queries/pg_stat_statements_reset.sql
104
108
  - lib/ruby-pg-extras/queries/records_rank.sql
105
109
  - lib/ruby-pg-extras/queries/seq_scans.sql
110
+ - lib/ruby-pg-extras/queries/ssl_used.sql
106
111
  - lib/ruby-pg-extras/queries/table_cache_hit.sql
107
112
  - lib/ruby-pg-extras/queries/table_indexes_size.sql
108
113
  - lib/ruby-pg-extras/queries/table_size.sql
@@ -133,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
138
  - !ruby/object:Gem::Version
134
139
  version: '0'
135
140
  requirements: []
136
- rubygems_version: 3.1.4
141
+ rubygems_version: 3.1.6
137
142
  signing_key:
138
143
  specification_version: 4
139
144
  summary: Ruby PostgreSQL performance database insights