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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e51c5c9ce5c31760d773177a3b224674752b19de8cc9fa0978e1da2adff9a490
4
- data.tar.gz: ce9b2e89d2524aafda39bd5a91bb53abde5d0819e0c8751281a5ff7ad10766c2
3
+ metadata.gz: c797cdeb10797636a6406b017fc9276ea6522656f6592769b5088bee56165cfb
4
+ data.tar.gz: 76dc688fcea9ccde4aead259ef582f6103d62a5f40e7be668ee2b03347a14470
5
5
  SHA512:
6
- metadata.gz: 63cdf589a11ab232f45e26ff8b6a713ef757ce3bc3baf3fecbc51217fb4c3a4bdda0ded52bc631bbb8aaa5fe7ca28d356ab99e200c5af22a3bd1bac9e5efc17b
7
- data.tar.gz: fcbb680a98f5907a62216ee142fa91b8538965c1fd59c1de48645ee1b5e3525950245d010a128f52b28fda665d0f6fcbf95fa343184b559150646819049f173a
6
+ metadata.gz: a5ac6bf812b56648ac0b1f864baf025b7cd4e81cccf6d6de65f1780fd63f8f1e640aff53aca771cece0ce54267ad7a428aaba8f42773591380547fac05bfe94a
7
+ data.tar.gz: 7c0f8b36467cc5eacbc96f6e5e2132de3526ea9827cab9c5ede7e1eff2b471f22948e0b202f1a00fd8b37b785934eec8508ad561947e50efa9b9ffb07e5eb9ae
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.3.5
2
+
3
+ - Added `sql` input format
4
+ - Fixed error for queries with double dash comments
5
+ - Fixed connection threading issue with `--pg-stat-activity` option
6
+
1
7
  ## 0.3.4
2
8
 
3
9
  - Fixed `--username` option
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: [master]
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
@@ -12,6 +12,7 @@ require "dexter/indexer"
12
12
  require "dexter/log_parser"
13
13
  require "dexter/csv_log_parser"
14
14
  require "dexter/pg_stat_activity_parser"
15
+ require "dexter/sql_log_parser"
15
16
  require "dexter/processor"
16
17
  require "dexter/query"
17
18
 
@@ -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 query_indexes.size == 1 && !query.suggest_index
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
- conn.exec_params(query, []).to_a
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
@@ -18,7 +18,7 @@ module Dexter
18
18
 
19
19
  queries = new_queries
20
20
 
21
- sleep(5)
21
+ sleep(1)
22
22
  end
23
23
  end
24
24
  end
@@ -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
@@ -0,0 +1,10 @@
1
+ module Dexter
2
+ class SqlLogParser < LogParser
3
+ def perform
4
+ # TODO support streaming
5
+ @logfile.read.split(";").each do |statement|
6
+ process_entry(statement, 1)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Dexter
2
- VERSION = "0.3.4"
2
+ VERSION = "0.3.5"
3
3
  end
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
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-10 00:00:00.000000000 Z
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