pgdexter 0.5.0 → 0.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: 65822d0d98c9641efdc3146295e098e09e83348ed109b856670a03d74ed2d70b
4
- data.tar.gz: 6d16c9019172e5e69df056ac358588151fa52ae9e8256159547e1842e2f9b97c
3
+ metadata.gz: e51edc18f4049b9ca811e4662248aa7a23e748b000975a87fa4a431f49ec632b
4
+ data.tar.gz: f3aa243431e0aab1d84d4cbc48ee6a329581acedc7a9c70e2a13e7bb0e15b529
5
5
  SHA512:
6
- metadata.gz: 4991adea5ee65493ea99abe94c19360fc6cc718048784431409abc08fbaf1b1efe3b304dedbd0994d8b66b38294b41ea6400bf5de1f03f09694723a7b709e77c
7
- data.tar.gz: 00f47a3efd2de6565dd5f5a3a64caa4b610e282d16620975376876501130a6d0cdbbef9412254b8f3d09db2df7a1f3f62d3a8e581c4fcfecd27ea3224cb6f20f
6
+ metadata.gz: 67b04a3c336c3bec239490a386825153699c646a01f5fe30d84b42445695f2431b1545bace72c5b955e03e92ad531810b5a73971d559abb06f175a1965454b89
7
+ data.tar.gz: 63691b01566b54056201c2d0a5c73a8153252b7c2ce4619983feb3b20e58d49d4a738b210be61d46231d3b5c78c1787664c625c0eb0216ee0d9ba19dcc8a7621
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 0.5.2 (2024-01-10)
2
+
3
+ - Added Docker image for `linux/arm64`
4
+ - Switched to `GENERIC_PLAN` for Postgres 16
5
+ - Fixed error with `auto_explain`
6
+ - Fixed warning with Ruby 3.3
7
+
8
+ ## 0.5.1 (2023-05-27)
9
+
10
+ - Fixed `JSON::NestingError`
11
+
1
12
  ## 0.5.0 (2023-04-18)
2
13
 
3
14
  - Added support for normalized queries
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017-2023 Andrew Kane
1
+ Copyright (c) 2017-2024 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -4,7 +4,7 @@ The automatic indexer for Postgres
4
4
 
5
5
  [Read about how it works](https://ankane.org/introducing-dexter) or [watch the talk](https://www.youtube.com/watch?v=Mni_1yTaNbE)
6
6
 
7
- [![Build Status](https://github.com/ankane/dexter/workflows/build/badge.svg?branch=master)](https://github.com/ankane/dexter/actions)
7
+ [![Build Status](https://github.com/ankane/dexter/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/dexter/actions)
8
8
 
9
9
  ## Installation
10
10
 
@@ -12,8 +12,8 @@ First, install [HypoPG](https://github.com/HypoPG/hypopg) on your database serve
12
12
 
13
13
  ```sh
14
14
  cd /tmp
15
- curl -L https://github.com/HypoPG/hypopg/archive/1.3.1.tar.gz | tar xz
16
- cd hypopg-1.3.1
15
+ curl -L https://github.com/HypoPG/hypopg/archive/1.4.0.tar.gz | tar xz
16
+ cd hypopg-1.4.0
17
17
  make
18
18
  make install # may need sudo
19
19
  ```
@@ -174,26 +174,6 @@ When streaming logs, specify the time to wait between processing queries
174
174
  dexter --interval 60 # seconds
175
175
  ```
176
176
 
177
- ## Examples
178
-
179
- Postgres package on Ubuntu 22.04
180
-
181
- ```sh
182
- sudo -u postgres dexter -d dbname /var/log/postgresql/postgresql-14-main.log
183
- ```
184
-
185
- Homebrew Postgres on Mac ARM
186
-
187
- ```sh
188
- dexter -d dbname /opt/homebrew/var/log/postgresql@14.log
189
- ```
190
-
191
- Homebrew Postgres on Mac x86-64
192
-
193
- ```sh
194
- dexter -d dbname /usr/local/var/log/postgresql@14.log
195
- ```
196
-
197
177
  ## Analyze
198
178
 
199
179
  For best results, make sure your tables have been recently analyzed so statistics are up-to-date. You can ask Dexter to analyze tables it comes across that haven’t been analyzed in the past hour with:
@@ -230,9 +210,8 @@ The `hypopg` extension, which Dexter needs to run, is available on [these provid
230
210
 
231
211
  For other providers, see [this guide](guides/Hosted-Postgres.md). To request a new extension:
232
212
 
233
- - Amazon RDS - follow the instructions on [this page](https://aws.amazon.com/rds/postgresql/faqs/)
234
213
  - Google Cloud SQL - vote or comment on [this page](https://issuetracker.google.com/issues/69250435)
235
- - DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/app-framework-services/p/support-hypopg-for-postgres)
214
+ - DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/managed-database/p/support-hypopg-for-postgres)
236
215
 
237
216
  ## HypoPG Installation Notes
238
217
 
@@ -185,7 +185,7 @@ module Dexter
185
185
 
186
186
  # get initial costs for queries
187
187
  calculate_plan(queries)
188
- explainable_queries = queries.select { |q| q.explainable? && q.high_cost? }
188
+ explainable_queries = queries.select { |q| q.plans.any? && q.high_cost? }
189
189
 
190
190
  # filter tables for performance
191
191
  tables = Set.new(explainable_queries.flat_map(&:tables))
@@ -197,10 +197,16 @@ module Dexter
197
197
  possible_columns = Set.new
198
198
  explainable_queries.each do |query|
199
199
  log "Finding columns: #{query.statement}" if @log_level == "debug3"
200
- find_columns(query.tree).each do |col|
201
- last_col = col["fields"].last
202
- if last_col["String"]
203
- possible_columns << last_col["String"]["sval"]
200
+ begin
201
+ find_columns(query.tree).each do |col|
202
+ last_col = col["fields"].last
203
+ if last_col["String"]
204
+ possible_columns << last_col["String"]["sval"]
205
+ end
206
+ end
207
+ rescue JSON::NestingError
208
+ if @log_level.start_with?("debug")
209
+ log colorize("ERROR: Cannot get columns", :red)
204
210
  end
205
211
  end
206
212
  end
@@ -226,7 +232,7 @@ module Dexter
226
232
  end
227
233
 
228
234
  def find_columns(plan)
229
- plan = JSON.parse(plan.to_json)
235
+ plan = JSON.parse(plan.to_json, max_nesting: 1000)
230
236
  find_by_key(plan, "ColumnRef")
231
237
  end
232
238
 
@@ -515,8 +521,8 @@ module Dexter
515
521
  raise Dexter::Abort, e.message
516
522
  end
517
523
 
518
- def execute(query, pretty: true, params: [])
519
- # use exec_params instead of exec for security
524
+ def execute(query, pretty: true, params: [], use_exec: false)
525
+ # use exec_params instead of exec when possible for security
520
526
  #
521
527
  # Unlike PQexec, PQexecParams allows at most one SQL command in the given string.
522
528
  # (There can be semicolons in it, but not more than one nonempty command.)
@@ -527,7 +533,11 @@ module Dexter
527
533
  log colorize("[sql] #{query}#{params.any? ? " /*#{params.to_json}*/" : ""}", :cyan) if @log_sql
528
534
 
529
535
  @mutex.synchronize do
530
- conn.exec_params("#{query} /*dexter*/", params).to_a
536
+ if use_exec
537
+ conn.exec("#{query} /*dexter*/").to_a
538
+ else
539
+ conn.exec_params("#{query} /*dexter*/", params).to_a
540
+ end
531
541
  end
532
542
  end
533
543
 
@@ -537,7 +547,9 @@ module Dexter
537
547
 
538
548
  # try to EXPLAIN normalized queries
539
549
  # https://dev.to/yugabyte/explain-from-pgstatstatements-normalized-queries-how-to-always-get-the-generic-plan-in--5cfi
540
- explain_normalized = query.include?("$1")
550
+ normalized = query.include?("$1")
551
+ generic_plan = normalized && server_version_num >= 160000
552
+ explain_normalized = normalized && !generic_plan
541
553
  if explain_normalized
542
554
  prepared_name = "dexter_prepared"
543
555
  execute("PREPARE #{prepared_name} AS #{safe_statement(query)}", pretty: false)
@@ -560,12 +572,14 @@ module Dexter
560
572
  end
561
573
  end
562
574
 
575
+ explain_prefix = generic_plan ? "GENERIC_PLAN, " : ""
576
+
563
577
  # strip semi-colons as another measure of defense
564
- plan = JSON.parse(execute("EXPLAIN (FORMAT JSON) #{safe_statement(query)}", pretty: false).first["QUERY PLAN"], max_nesting: 1000).first["Plan"]
578
+ plan = JSON.parse(execute("EXPLAIN (#{explain_prefix}FORMAT JSON) #{safe_statement(query)}", pretty: false, use_exec: generic_plan).first["QUERY PLAN"], max_nesting: 1000).first["Plan"]
565
579
 
566
580
  if @log_explain
567
581
  # Pass format to prevent ANALYZE
568
- puts execute("EXPLAIN (FORMAT TEXT) #{safe_statement(query)}", pretty: false).map { |r| r["QUERY PLAN"] }.join("\n")
582
+ puts execute("EXPLAIN (#{explain_prefix}FORMAT TEXT) #{safe_statement(query)}", pretty: false, use_exec: generic_plan).map { |r| r["QUERY PLAN"] }.join("\n")
569
583
  end
570
584
 
571
585
  plan
data/lib/dexter/query.rb CHANGED
@@ -31,7 +31,7 @@ module Dexter
31
31
  end
32
32
 
33
33
  def explainable?
34
- plans.any?
34
+ plans.size >= 3
35
35
  end
36
36
 
37
37
  def costs
@@ -1,3 +1,3 @@
1
1
  module Dexter
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.2"
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgdexter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-18 00:00:00.000000000 Z
11
+ date: 2024-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: csv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: pg
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -96,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
110
  - !ruby/object:Gem::Version
97
111
  version: '0'
98
112
  requirements: []
99
- rubygems_version: 3.4.10
113
+ rubygems_version: 3.5.3
100
114
  signing_key:
101
115
  specification_version: 4
102
116
  summary: The automatic indexer for Postgres