pgdexter 0.3.10 → 0.4.1
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 +10 -0
- data/README.md +36 -6
- data/lib/dexter/indexer.rb +22 -13
- data/lib/dexter/json_log_parser.rb +23 -0
- data/lib/dexter/processor.rb +3 -1
- data/lib/dexter/version.rb +1 -1
- data/lib/dexter.rb +2 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 109808872c6a579e6ce82956d5b2b1da8c66af7c85fae3d5984367e374484eb2
|
4
|
+
data.tar.gz: 6fe0f25f316afd84c287ba2fefe5076846c8a572bf2cbee406843abf632ddb2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2e5b5d80869c5c90b234af5edbb6d0c0e6118a3dc7191c2d7169209c7ae1505329fb18ea5e3803b045a527dd20b2909a9b2067732dfa030bbce0a931fc88954
|
7
|
+
data.tar.gz: 03d139a0f6ac0e967ad4f98685a6d8e513eab0b2022c7a0f7c6d27eca0da9b6441c30480a19acacf5c5f5f0ec762a7243331c3ee752b071015800a98043cad3b
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
The automatic indexer for Postgres
|
4
4
|
|
5
|
-
[Read about how it works](https://ankane.org/introducing-dexter)
|
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
7
|
[](https://github.com/ankane/dexter/actions)
|
8
8
|
|
@@ -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.
|
16
|
-
cd hypopg-1.
|
15
|
+
curl -L https://github.com/HypoPG/hypopg/archive/1.3.1.tar.gz | tar xz
|
16
|
+
cd hypopg-1.3.1
|
17
17
|
make
|
18
18
|
make install # may need sudo
|
19
19
|
```
|
@@ -32,7 +32,7 @@ And install the command line tool with:
|
|
32
32
|
gem install pgdexter
|
33
33
|
```
|
34
34
|
|
35
|
-
The command line tool is also available as a [Linux package](guides/Linux.md).
|
35
|
+
The command line tool is also available with [Docker](#docker), [Homebrew](#homebrew), or as a [Linux package](guides/Linux.md).
|
36
36
|
|
37
37
|
## How to Use
|
38
38
|
|
@@ -190,7 +190,37 @@ dexter --log-sql --log-level debug2
|
|
190
190
|
|
191
191
|
## Hosted Postgres
|
192
192
|
|
193
|
-
Some hosted providers like Amazon RDS and Heroku do not support the HypoPG extension, which Dexter needs to run. See [how to use Dexter](guides/Hosted-Postgres.md) in these cases.
|
193
|
+
Some hosted providers like Amazon RDS and Heroku do not support the HypoPG extension, which Dexter needs to run. See [how to use Dexter](guides/Hosted-Postgres.md) in these cases. To request the extension:
|
194
|
+
|
195
|
+
- Amazon RDS - follow the instructions on [this page](https://aws.amazon.com/rds/postgresql/faqs/)
|
196
|
+
- Google Cloud SQL - star the [feature request](https://issuetracker.google.com/issues/69250435)
|
197
|
+
- DigitalOcean Managed Databases - follow the instructions on [this page](https://docs.digitalocean.com/products/databases/postgresql/details/supported-extensions/#supported-extensions)
|
198
|
+
|
199
|
+
## Additional Installation Methods
|
200
|
+
|
201
|
+
### Docker
|
202
|
+
|
203
|
+
Get the [Docker image](https://hub.docker.com/r/ankane/dexter) with:
|
204
|
+
|
205
|
+
```sh
|
206
|
+
docker pull ankane/dexter
|
207
|
+
```
|
208
|
+
|
209
|
+
And run it with:
|
210
|
+
|
211
|
+
```sh
|
212
|
+
docker run -ti ankane/dexter <connection-options>
|
213
|
+
```
|
214
|
+
|
215
|
+
For databases on the host machine, use `host.docker.internal` as the hostname (on Linux, this requires Docker 20.04 and `--add-host=host.docker.internal:host-gateway`).
|
216
|
+
|
217
|
+
### Homebrew
|
218
|
+
|
219
|
+
With Homebrew, you can use:
|
220
|
+
|
221
|
+
```sh
|
222
|
+
brew install ankane/brew/dexter
|
223
|
+
```
|
194
224
|
|
195
225
|
## Future Work
|
196
226
|
|
@@ -213,7 +243,7 @@ gem specific_install https://github.com/ankane/dexter.git
|
|
213
243
|
|
214
244
|
## Thanks
|
215
245
|
|
216
|
-
This software wouldn’t be possible without [HypoPG](https://github.com/
|
246
|
+
This software wouldn’t be possible without [HypoPG](https://github.com/HypoPG/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
247
|
|
218
248
|
## Research
|
219
249
|
|
data/lib/dexter/indexer.rb
CHANGED
@@ -240,6 +240,7 @@ module Dexter
|
|
240
240
|
end
|
241
241
|
|
242
242
|
def find_columns(plan)
|
243
|
+
plan = JSON.parse(plan.to_json)
|
243
244
|
find_by_key(plan, "ColumnRef")
|
244
245
|
end
|
245
246
|
|
@@ -248,20 +249,24 @@ module Dexter
|
|
248
249
|
end
|
249
250
|
|
250
251
|
def find_by_key(plan, key)
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
252
|
+
result = []
|
253
|
+
queue = [plan]
|
254
|
+
while queue.any?
|
255
|
+
node = queue.pop
|
256
|
+
case node
|
257
|
+
when Hash
|
258
|
+
node.each do |k, v|
|
259
|
+
if k == key
|
260
|
+
result << v
|
261
|
+
elsif !v.nil?
|
262
|
+
queue << v
|
263
|
+
end
|
259
264
|
end
|
265
|
+
when Array
|
266
|
+
queue.concat(node)
|
260
267
|
end
|
261
|
-
when Array
|
262
|
-
indexes.concat(plan.flat_map { |v| find_by_key(v, key) })
|
263
268
|
end
|
264
|
-
|
269
|
+
result
|
265
270
|
end
|
266
271
|
|
267
272
|
def hypo_indexes_from_plan(index_name_to_columns, plan, index_set)
|
@@ -483,10 +488,10 @@ module Dexter
|
|
483
488
|
statement = String.new("CREATE INDEX CONCURRENTLY ON #{quote_ident(index[:table])} (#{index[:columns].map { |c| quote_ident(c) }.join(", ")})")
|
484
489
|
statement << " TABLESPACE #{quote_ident(@tablespace)}" if @tablespace
|
485
490
|
log "Creating index: #{statement}"
|
486
|
-
started_at =
|
491
|
+
started_at = monotonic_time
|
487
492
|
begin
|
488
493
|
execute(statement)
|
489
|
-
log "Index created: #{((
|
494
|
+
log "Index created: #{((monotonic_time - started_at) * 1000).to_i} ms"
|
490
495
|
rescue PG::LockNotAvailable
|
491
496
|
log "Could not acquire lock: #{index[:table]}"
|
492
497
|
end
|
@@ -498,6 +503,10 @@ module Dexter
|
|
498
503
|
new_indexes
|
499
504
|
end
|
500
505
|
|
506
|
+
def monotonic_time
|
507
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
508
|
+
end
|
509
|
+
|
501
510
|
def conn
|
502
511
|
@conn ||= begin
|
503
512
|
# set connect timeout if none set
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Dexter
|
4
|
+
class JsonLogParser < LogParser
|
5
|
+
FIRST_LINE_REGEX = /\A.+/
|
6
|
+
|
7
|
+
def perform
|
8
|
+
@logfile.each_line do |line|
|
9
|
+
row = JSON.parse(line.chomp)
|
10
|
+
if (m = REGEX.match(row["message"]))
|
11
|
+
# replace first line with match
|
12
|
+
# needed for multiline queries
|
13
|
+
active_line = row["message"].sub(FIRST_LINE_REGEX, m[3])
|
14
|
+
|
15
|
+
add_parameters(active_line, row["detail"]) if row["detail"]
|
16
|
+
process_entry(active_line, m[1].to_f)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
rescue JSON::ParserError => e
|
20
|
+
raise Dexter::Abort, "ERROR: #{e.message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
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] == "json"
|
17
|
+
JsonLogParser.new(logfile, @collector)
|
16
18
|
elsif options[:input_format] == "sql"
|
17
19
|
SqlLogParser.new(logfile, @collector)
|
18
20
|
else
|
@@ -62,7 +64,7 @@ module Dexter
|
|
62
64
|
end
|
63
65
|
|
64
66
|
def process_queries_without_lock
|
65
|
-
now =
|
67
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
66
68
|
min_checked_at = now - 3600 # don't recheck for an hour
|
67
69
|
queries = []
|
68
70
|
@collector.fetch_queries.each do |query|
|
data/lib/dexter/version.rb
CHANGED
data/lib/dexter.rb
CHANGED
@@ -4,6 +4,7 @@ require "pg_query"
|
|
4
4
|
require "slop"
|
5
5
|
|
6
6
|
# stdlib
|
7
|
+
require "json"
|
7
8
|
require "set"
|
8
9
|
require "time"
|
9
10
|
|
@@ -15,6 +16,7 @@ require "dexter/collector"
|
|
15
16
|
require "dexter/indexer"
|
16
17
|
require "dexter/log_parser"
|
17
18
|
require "dexter/csv_log_parser"
|
19
|
+
require "dexter/json_log_parser"
|
18
20
|
require "dexter/pg_stat_activity_parser"
|
19
21
|
require "dexter/sql_log_parser"
|
20
22
|
require "dexter/processor"
|
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.
|
4
|
+
version: 0.4.1
|
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: 2022-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slop
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: pg_query
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '2'
|
47
|
+
version: '2.1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '2'
|
54
|
+
version: '2.1'
|
55
55
|
description:
|
56
56
|
email: andrew@ankane.org
|
57
57
|
executables:
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/dexter/collector.rb
|
69
69
|
- lib/dexter/csv_log_parser.rb
|
70
70
|
- lib/dexter/indexer.rb
|
71
|
+
- lib/dexter/json_log_parser.rb
|
71
72
|
- lib/dexter/log_parser.rb
|
72
73
|
- lib/dexter/logging.rb
|
73
74
|
- lib/dexter/pg_stat_activity_parser.rb
|
@@ -87,14 +88,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
88
|
requirements:
|
88
89
|
- - ">="
|
89
90
|
- !ruby/object:Gem::Version
|
90
|
-
version: '2.
|
91
|
+
version: '2.5'
|
91
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
93
|
requirements:
|
93
94
|
- - ">="
|
94
95
|
- !ruby/object:Gem::Version
|
95
96
|
version: '0'
|
96
97
|
requirements: []
|
97
|
-
rubygems_version: 3.
|
98
|
+
rubygems_version: 3.3.7
|
98
99
|
signing_key:
|
99
100
|
specification_version: 4
|
100
101
|
summary: The automatic indexer for Postgres
|