pghero 1.3.2 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pghero might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/app/controllers/pg_hero/home_controller.rb +4 -1
- data/app/views/pg_hero/home/_live_queries_table.html.erb +2 -1
- data/app/views/pg_hero/home/_suggested_index.html.erb +1 -1
- data/app/views/pg_hero/home/index.html.erb +1 -1
- data/lib/pghero/methods/basic.rb +10 -1
- data/lib/pghero/methods/indexes.rb +2 -2
- data/lib/pghero/methods/kill.rb +1 -1
- data/lib/pghero/methods/query_stats.rb +9 -4
- data/lib/pghero/version.rb +1 -1
- data/test/gemfiles/activerecord42.gemfile +6 -0
- data/test/suggested_indexes_test.rb +8 -3
- data/test/test_helper.rb +4 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c54bcd3e6419f74fe1bc9ad92ab5424ccde607d
|
4
|
+
data.tar.gz: a3a347148aad3b70bca436c805472a2dee80096f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a942b06fd72ba880d7c73b0bc3e35807d4a6f7c9ebe5b3df8ef2a8e131f8ab92871d1ca94b2c0eb35ca95cfe9d6d02efcc123741fecd66db9730dc70eafad3f0
|
7
|
+
data.tar.gz: d9727509fea173d2c698b2eddafd04834ef006f9c9463be61b0b9582bc555f0d894b34ee075dd8adc537489c575fc89257411f4083b3a690bc8ab47562a4e7f7
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -33,7 +33,10 @@ module PgHero
|
|
33
33
|
@invalid_indexes = PgHero.invalid_indexes
|
34
34
|
@duplicate_indexes = PgHero.duplicate_indexes if params[:duplicate_indexes]
|
35
35
|
@good_cache_rate = @table_hit_rate >= PgHero.cache_hit_rate_threshold.to_f / 100 && @index_hit_rate >= PgHero.cache_hit_rate_threshold.to_f / 100
|
36
|
-
@
|
36
|
+
unless @query_stats_enabled
|
37
|
+
@query_stats_available = PgHero.query_stats_available?
|
38
|
+
@query_stats_extension_enabled = PgHero.query_stats_extension_enabled? if @query_stats_available
|
39
|
+
end
|
37
40
|
@total_connections = PgHero.total_connections
|
38
41
|
@good_total_connections = @total_connections < PgHero.total_connections_threshold
|
39
42
|
if @replica
|
@@ -17,7 +17,8 @@
|
|
17
17
|
<td><%= query["started_at"] ? "#{number_with_delimiter(((now - Time.parse(query["started_at"])) * 1000).round)} ms" : nil %></td>
|
18
18
|
<td><%= query["source"] %> <span class="text-muted"><%= query["user"] %></span></td>
|
19
19
|
<td class="text-right">
|
20
|
-
|
20
|
+
<% button_path, button_options = Rails.version >= "4.1" ? [explain_path, {params: {query: query["query"]}}] : [explain_path(query: query["query"]), {}] %>
|
21
|
+
<%= button_to "Explain", button_path, button_options.merge(form: {target: "_blank"}, class: "btn btn-info") %>
|
21
22
|
<%= button_to "Kill", kill_path(pid: query["pid"]), class: "btn btn-danger" %>
|
22
23
|
</td>
|
23
24
|
</tr>
|
@@ -13,6 +13,6 @@ Row estimates
|
|
13
13
|
<%= details[:row_estimates].to_a.map { |k, v| "- #{k}: #{v}" }.join("\n") %><% end %><% if details[:table_indexes] %>
|
14
14
|
|
15
15
|
Existing indexes
|
16
|
-
<% details[:table_indexes].sort_by { |i| [i["primary"]
|
16
|
+
<% details[:table_indexes].sort_by { |i| [PgHero.truthy?(i["primary"]) ? 0 : 1, i["columns"]] }.each do |i3| %>- <%= i3["columns"].join(", ") %><% if i3["using"] != "btree" %> <%= i3["using"].to_s.upcase %><% end %><% if PgHero.truthy?(i3["primary"]) %> PRIMARY<% elsif PgHero.truthy?(i3["unique"]) %> UNIQUE<% end %>
|
17
17
|
<% end %><% end %></pre></code>
|
18
18
|
</div>
|
@@ -317,7 +317,7 @@ add_index <%= index[:table].to_sym.inspect %>, [<%= index[:columns].map(&:to_sym
|
|
317
317
|
<div class="content">
|
318
318
|
<h1>Query Stats</h1>
|
319
319
|
|
320
|
-
<% if @query_stats_available %>
|
320
|
+
<% if @query_stats_available && !@query_stats_extension_enabled %>
|
321
321
|
<p>
|
322
322
|
Query stats are available but not enabled.
|
323
323
|
<%= button_to "Enable", enable_query_stats_path, class: "btn btn-info" %>
|
data/lib/pghero/methods/basic.rb
CHANGED
@@ -45,12 +45,21 @@ module PgHero
|
|
45
45
|
ssl_used = nil
|
46
46
|
connection_model.transaction do
|
47
47
|
execute("CREATE EXTENSION IF NOT EXISTS sslinfo")
|
48
|
-
ssl_used = select_all("SELECT ssl_is_used()").first["ssl_is_used"]
|
48
|
+
ssl_used = truthy?(select_all("SELECT ssl_is_used()").first["ssl_is_used"])
|
49
49
|
raise ActiveRecord::Rollback
|
50
50
|
end
|
51
51
|
ssl_used
|
52
52
|
end
|
53
53
|
|
54
|
+
# Handles Rails 4 ('t') and Rails 5 (true) values.
|
55
|
+
def truthy?(value)
|
56
|
+
value == true || value == 't'
|
57
|
+
end
|
58
|
+
|
59
|
+
def falsey?(value)
|
60
|
+
value == false || value == 'f'
|
61
|
+
end
|
62
|
+
|
54
63
|
private
|
55
64
|
|
56
65
|
def friendly_value(setting, unit)
|
@@ -140,8 +140,8 @@ module PgHero
|
|
140
140
|
indexes = []
|
141
141
|
|
142
142
|
indexes_by_table = self.indexes.group_by { |i| i["table"] }
|
143
|
-
indexes_by_table.values.flatten.select { |i| i["primary"]
|
144
|
-
covering_index = indexes_by_table[index["table"]].find { |i| index_covers?(i["columns"], index["columns"]) && i["using"] == index["using"] && i["name"] != index["name"] && i["valid"]
|
143
|
+
indexes_by_table.values.flatten.select { |i| falsey?(i["primary"]) && falsey?(i["unique"]) && !i["indexprs"] && !i["indpred"] && truthy?(i["valid"]) }.each do |index|
|
144
|
+
covering_index = indexes_by_table[index["table"]].find { |i| index_covers?(i["columns"], index["columns"]) && i["using"] == index["using"] && i["name"] != index["name"] && truthy?(i["valid"]) }
|
145
145
|
if covering_index
|
146
146
|
indexes << {"unneeded_index" => index, "covering_index" => covering_index}
|
147
147
|
end
|
data/lib/pghero/methods/kill.rb
CHANGED
@@ -2,7 +2,7 @@ module PgHero
|
|
2
2
|
module Methods
|
3
3
|
module Kill
|
4
4
|
def kill(pid)
|
5
|
-
execute("SELECT pg_terminate_backend(#{pid.to_i})").first["pg_terminate_backend"]
|
5
|
+
truthy? execute("SELECT pg_terminate_backend(#{pid.to_i})").first["pg_terminate_backend"]
|
6
6
|
end
|
7
7
|
|
8
8
|
def kill_long_running_queries
|
@@ -31,11 +31,16 @@ module PgHero
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def query_stats_enabled?
|
34
|
-
|
34
|
+
query_stats_extension_enabled? && query_stats_readable?
|
35
|
+
end
|
36
|
+
|
37
|
+
def query_stats_extension_enabled?
|
38
|
+
select_all("SELECT COUNT(*) AS count FROM pg_extension WHERE extname = 'pg_stat_statements'").first["count"].to_i > 0
|
35
39
|
end
|
36
40
|
|
37
41
|
def query_stats_readable?
|
38
|
-
select_all("SELECT
|
42
|
+
select_all("SELECT * FROM pg_stat_statements LIMIT 1")
|
43
|
+
true
|
39
44
|
rescue ActiveRecord::StatementInvalid
|
40
45
|
false
|
41
46
|
end
|
@@ -116,7 +121,7 @@ module PgHero
|
|
116
121
|
# http://stackoverflow.com/questions/20582500/how-to-check-if-a-table-exists-in-a-given-schema
|
117
122
|
def historical_query_stats_enabled?
|
118
123
|
# TODO use schema from config
|
119
|
-
stats_connection.select_all(squish <<-SQL
|
124
|
+
truthy? stats_connection.select_all(squish <<-SQL
|
120
125
|
SELECT EXISTS (
|
121
126
|
SELECT
|
122
127
|
1
|
@@ -130,7 +135,7 @@ module PgHero
|
|
130
135
|
AND c.relkind = 'r'
|
131
136
|
)
|
132
137
|
SQL
|
133
|
-
).to_a.first["exists"]
|
138
|
+
).to_a.first["exists"]
|
134
139
|
end
|
135
140
|
|
136
141
|
def stats_connection
|
data/lib/pghero/version.rb
CHANGED
@@ -2,14 +2,19 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
class SuggestedIndexesTest < Minitest::Test
|
4
4
|
def setup
|
5
|
+
# no pg_stat_statements
|
6
|
+
skip if ENV["TRAVIS_CI"]
|
7
|
+
|
5
8
|
PgHero.reset_query_stats
|
6
9
|
end
|
7
10
|
|
8
11
|
def test_basic
|
9
|
-
# no pg_stat_statements
|
10
|
-
skip if ENV["TRAVIS_CI"]
|
11
|
-
|
12
12
|
User.where(email: "person1@example.org").first
|
13
13
|
assert_equal [{table: "users", columns: ["email"]}], PgHero.suggested_indexes.map { |q| q.except(:queries, :details) }
|
14
14
|
end
|
15
|
+
|
16
|
+
def test_existing_index
|
17
|
+
User.where("updated_at > ?", Time.now).to_a
|
18
|
+
assert_equal [], PgHero.suggested_indexes.map { |q| q.except(:queries, :details) }
|
19
|
+
end
|
15
20
|
end
|
data/test/test_helper.rb
CHANGED
@@ -31,7 +31,9 @@ unless ENV["SKIP_SEED"]
|
|
31
31
|
t.string :zip_code
|
32
32
|
t.boolean :active
|
33
33
|
t.timestamp :created_at
|
34
|
+
t.timestamp :updated_at
|
34
35
|
end
|
36
|
+
ActiveRecord::Migration.add_index :users, :updated_at
|
35
37
|
|
36
38
|
User.transaction do
|
37
39
|
users =
|
@@ -43,7 +45,8 @@ unless ENV["SKIP_SEED"]
|
|
43
45
|
login_attempts: rand(30),
|
44
46
|
zip_code: i % 40 == 0 ? nil : "12345",
|
45
47
|
active: true,
|
46
|
-
created_at: Time.now - rand(50).days
|
48
|
+
created_at: Time.now - rand(50).days,
|
49
|
+
updated_at: Time.now - rand(50).days
|
47
50
|
)
|
48
51
|
end
|
49
52
|
User.import users, validate: false
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pghero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -175,6 +175,7 @@ files:
|
|
175
175
|
- test/best_index_test.rb
|
176
176
|
- test/explain_test.rb
|
177
177
|
- test/gemfiles/activerecord41.gemfile
|
178
|
+
- test/gemfiles/activerecord42.gemfile
|
178
179
|
- test/suggested_indexes_test.rb
|
179
180
|
- test/test_helper.rb
|
180
181
|
homepage: https://github.com/ankane/pghero
|
@@ -211,6 +212,7 @@ test_files:
|
|
211
212
|
- test/best_index_test.rb
|
212
213
|
- test/explain_test.rb
|
213
214
|
- test/gemfiles/activerecord41.gemfile
|
215
|
+
- test/gemfiles/activerecord42.gemfile
|
214
216
|
- test/suggested_indexes_test.rb
|
215
217
|
- test/test_helper.rb
|
216
218
|
has_rdoc:
|