pgdexter 0.3.4 → 0.3.5
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 +6 -0
- data/README.md +6 -1
- data/lib/dexter.rb +1 -0
- data/lib/dexter/indexer.rb +14 -9
- data/lib/dexter/pg_stat_activity_parser.rb +1 -1
- data/lib/dexter/processor.rb +2 -0
- data/lib/dexter/sql_log_parser.rb +10 -0
- data/lib/dexter/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c797cdeb10797636a6406b017fc9276ea6522656f6592769b5088bee56165cfb
|
4
|
+
data.tar.gz: 76dc688fcea9ccde4aead259ef582f6103d62a5f40e7be668ee2b03347a14470
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5ac6bf812b56648ac0b1f864baf025b7cd4e81cccf6d6de65f1780fd63f8f1e640aff53aca771cece0ce54267ad7a428aaba8f42773591380547fac05bfe94a
|
7
|
+
data.tar.gz: 7c0f8b36467cc5eacbc96f6e5e2132de3526ea9827cab9c5ede7e1eff2b471f22948e0b202f1a00fd8b37b785934eec8508ad561947e50efa9b9ffb07e5eb9ae
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -104,7 +104,7 @@ or pass files:
|
|
104
104
|
dexter <connection-options> <file1> <file2>
|
105
105
|
```
|
106
106
|
|
107
|
-
or collect running queries with:
|
107
|
+
or collect running queries with:
|
108
108
|
|
109
109
|
```sh
|
110
110
|
dexter <connection-options> --pg-stat-activity
|
@@ -215,6 +215,10 @@ gem specific_install https://github.com/ankane/dexter.git
|
|
215
215
|
|
216
216
|
This software wouldn’t be possible without [HypoPG](https://github.com/dalibo/hypopg), which allows you to create hypothetical indexes, and [pg_query](https://github.com/lfittl/pg_query), which allows you to parse and fingerprint queries. A big thanks to Dalibo and Lukas Fittl respectively.
|
217
217
|
|
218
|
+
## Research
|
219
|
+
|
220
|
+
This is known as the Index Selection Problem (ISP).
|
221
|
+
|
218
222
|
## Contributing
|
219
223
|
|
220
224
|
Everyone is encouraged to help improve this project. Here are a few ways you can help:
|
@@ -236,5 +240,6 @@ rake install
|
|
236
240
|
To run tests, use:
|
237
241
|
|
238
242
|
```sh
|
243
|
+
createdb dexter_test
|
239
244
|
rake test
|
240
245
|
```
|
data/lib/dexter.rb
CHANGED
data/lib/dexter/indexer.rb
CHANGED
@@ -14,6 +14,7 @@ module Dexter
|
|
14
14
|
@analyze = options[:analyze]
|
15
15
|
@min_cost_savings_pct = options[:min_cost_savings_pct].to_i
|
16
16
|
@options = options
|
17
|
+
@mutex = Mutex.new
|
17
18
|
|
18
19
|
create_extension unless extension_exists?
|
19
20
|
execute("SET lock_timeout = '5s'")
|
@@ -181,7 +182,7 @@ module Dexter
|
|
181
182
|
query.plans << plan(query.statement)
|
182
183
|
if @log_explain
|
183
184
|
# Pass format to prevent ANALYZE
|
184
|
-
puts execute("EXPLAIN (FORMAT TEXT) #{safe_statement(query.statement)}").map { |r| r["QUERY PLAN"] }.join("\n")
|
185
|
+
puts execute("EXPLAIN (FORMAT TEXT) #{safe_statement(query.statement)}", pretty: false).map { |r| r["QUERY PLAN"] }.join("\n")
|
185
186
|
end
|
186
187
|
rescue PG::Error, JSON::NestingError => e
|
187
188
|
if @log_explain
|
@@ -362,11 +363,12 @@ module Dexter
|
|
362
363
|
winning_cost < query.initial_cost * savings_ratio
|
363
364
|
end
|
364
365
|
|
366
|
+
query_indexes = [winning_index]
|
367
|
+
new_cost3 = winning_cost
|
368
|
+
query.pass3_indexes = query_indexes
|
369
|
+
|
365
370
|
if use_winning
|
366
|
-
query_indexes = [winning_index]
|
367
371
|
cost_savings3 = true
|
368
|
-
new_cost3 = winning_cost
|
369
|
-
query.pass3_indexes = query_indexes
|
370
372
|
else
|
371
373
|
suggest_index = false
|
372
374
|
end
|
@@ -456,7 +458,7 @@ module Dexter
|
|
456
458
|
log "Pass3: #{query.costs[3]} : #{log_indexes(query.pass3_indexes || [])}"
|
457
459
|
end
|
458
460
|
log "Final: #{query.new_cost} : #{log_indexes(query.suggest_index ? query_indexes : [])}"
|
459
|
-
if
|
461
|
+
if (query.pass1_indexes.any? || query.pass2_indexes.any?) && !query.suggest_index
|
460
462
|
log "Need #{@min_cost_savings_pct}% cost savings to suggest index"
|
461
463
|
end
|
462
464
|
else
|
@@ -516,7 +518,7 @@ module Dexter
|
|
516
518
|
abort e.message
|
517
519
|
end
|
518
520
|
|
519
|
-
def execute(query)
|
521
|
+
def execute(query, pretty: true)
|
520
522
|
# use exec_params instead of exec for security
|
521
523
|
#
|
522
524
|
# Unlike PQexec, PQexecParams allows at most one SQL command in the given string.
|
@@ -524,14 +526,17 @@ module Dexter
|
|
524
526
|
# This is a limitation of the underlying protocol, but has some usefulness
|
525
527
|
# as an extra defense against SQL-injection attacks.
|
526
528
|
# https://www.postgresql.org/docs/current/static/libpq-exec.html
|
527
|
-
query = squish(query)
|
529
|
+
query = squish(query) if pretty
|
528
530
|
log "SQL: #{query}" if @log_sql
|
529
|
-
|
531
|
+
|
532
|
+
@mutex.synchronize do
|
533
|
+
conn.exec_params(query, []).to_a
|
534
|
+
end
|
530
535
|
end
|
531
536
|
|
532
537
|
def plan(query)
|
533
538
|
# strip semi-colons as another measure of defense
|
534
|
-
JSON.parse(execute("EXPLAIN (FORMAT JSON) #{safe_statement(query)}").first["QUERY PLAN"], max_nesting: 1000).first["Plan"]
|
539
|
+
JSON.parse(execute("EXPLAIN (FORMAT JSON) #{safe_statement(query)}", pretty: false).first["QUERY PLAN"], max_nesting: 1000).first["Plan"]
|
535
540
|
end
|
536
541
|
|
537
542
|
# TODO for multicolumn indexes, use ordering
|
data/lib/dexter/processor.rb
CHANGED
@@ -13,6 +13,8 @@ module Dexter
|
|
13
13
|
PgStatActivityParser.new(@indexer, @collector)
|
14
14
|
elsif options[:input_format] == "csv"
|
15
15
|
CsvLogParser.new(logfile, @collector)
|
16
|
+
elsif options[:input_format] == "sql"
|
17
|
+
SqlLogParser.new(logfile, @collector)
|
16
18
|
else
|
17
19
|
LogParser.new(logfile, @collector)
|
18
20
|
end
|
data/lib/dexter/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pgdexter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slop
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- lib/dexter/pg_stat_activity_parser.rb
|
123
123
|
- lib/dexter/processor.rb
|
124
124
|
- lib/dexter/query.rb
|
125
|
+
- lib/dexter/sql_log_parser.rb
|
125
126
|
- lib/dexter/version.rb
|
126
127
|
- pgdexter.gemspec
|
127
128
|
homepage: https://github.com/ankane/dexter
|