pgdexter 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|