pgdexter 0.5.1 → 0.5.2
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/dexter/indexer.rb +15 -7
- data/lib/dexter/query.rb +1 -1
- data/lib/dexter/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e51edc18f4049b9ca811e4662248aa7a23e748b000975a87fa4a431f49ec632b
|
4
|
+
data.tar.gz: f3aa243431e0aab1d84d4cbc48ee6a329581acedc7a9c70e2a13e7bb0e15b529
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67b04a3c336c3bec239490a386825153699c646a01f5fe30d84b42445695f2431b1545bace72c5b955e03e92ad531810b5a73971d559abb06f175a1965454b89
|
7
|
+
data.tar.gz: 63691b01566b54056201c2d0a5c73a8153252b7c2ce4619983feb3b20e58d49d4a738b210be61d46231d3b5c78c1787664c625c0eb0216ee0d9ba19dcc8a7621
|
data/CHANGELOG.md
CHANGED
data/LICENSE.txt
CHANGED
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
|
-
[](https://github.com/ankane/dexter/actions)
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
data/lib/dexter/indexer.rb
CHANGED
@@ -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.
|
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))
|
@@ -521,8 +521,8 @@ module Dexter
|
|
521
521
|
raise Dexter::Abort, e.message
|
522
522
|
end
|
523
523
|
|
524
|
-
def execute(query, pretty: true, params: [])
|
525
|
-
# 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
|
526
526
|
#
|
527
527
|
# Unlike PQexec, PQexecParams allows at most one SQL command in the given string.
|
528
528
|
# (There can be semicolons in it, but not more than one nonempty command.)
|
@@ -533,7 +533,11 @@ module Dexter
|
|
533
533
|
log colorize("[sql] #{query}#{params.any? ? " /*#{params.to_json}*/" : ""}", :cyan) if @log_sql
|
534
534
|
|
535
535
|
@mutex.synchronize do
|
536
|
-
|
536
|
+
if use_exec
|
537
|
+
conn.exec("#{query} /*dexter*/").to_a
|
538
|
+
else
|
539
|
+
conn.exec_params("#{query} /*dexter*/", params).to_a
|
540
|
+
end
|
537
541
|
end
|
538
542
|
end
|
539
543
|
|
@@ -543,7 +547,9 @@ module Dexter
|
|
543
547
|
|
544
548
|
# try to EXPLAIN normalized queries
|
545
549
|
# https://dev.to/yugabyte/explain-from-pgstatstatements-normalized-queries-how-to-always-get-the-generic-plan-in--5cfi
|
546
|
-
|
550
|
+
normalized = query.include?("$1")
|
551
|
+
generic_plan = normalized && server_version_num >= 160000
|
552
|
+
explain_normalized = normalized && !generic_plan
|
547
553
|
if explain_normalized
|
548
554
|
prepared_name = "dexter_prepared"
|
549
555
|
execute("PREPARE #{prepared_name} AS #{safe_statement(query)}", pretty: false)
|
@@ -566,12 +572,14 @@ module Dexter
|
|
566
572
|
end
|
567
573
|
end
|
568
574
|
|
575
|
+
explain_prefix = generic_plan ? "GENERIC_PLAN, " : ""
|
576
|
+
|
569
577
|
# strip semi-colons as another measure of defense
|
570
|
-
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"]
|
571
579
|
|
572
580
|
if @log_explain
|
573
581
|
# Pass format to prevent ANALYZE
|
574
|
-
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")
|
575
583
|
end
|
576
584
|
|
577
585
|
plan
|
data/lib/dexter/query.rb
CHANGED
data/lib/dexter/version.rb
CHANGED
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.
|
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:
|
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.
|
113
|
+
rubygems_version: 3.5.3
|
100
114
|
signing_key:
|
101
115
|
specification_version: 4
|
102
116
|
summary: The automatic indexer for Postgres
|