pghero 3.3.4 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2332e2a4f7b9bd25d972ec1f06635dfc43676412c5be4147e3a7e3dc8effa213
4
- data.tar.gz: 1a24e423a0d8749d69eb938eaa27db1beed974d1a058e6ae6331badeae9c4d59
3
+ metadata.gz: fe3a00850cccac8c36536d08a519790103053c9b058d61754f834c44cfb0d4eb
4
+ data.tar.gz: e7ae77f4353d7f27ca04f1a59aae6cf785f8e0dddac2f276e6a0973b4beb60e7
5
5
  SHA512:
6
- metadata.gz: b19ca11ceee2f44bbcdec49e14f0653df6efc740e4fbd710700a03254ac8d40db84690409a731c06359d547934d401615925e88df317ccae4137eecefcfe8ddf
7
- data.tar.gz: b6c0069a0e34ecd66d359aff9226fe678ccc15d55b1ad0e70f421a7fa9b9a2113d7eb31cc30d69364489fa1e10e2b5d6d0e48ada03d15e79aff5ba9dda350659
6
+ metadata.gz: 89d0bc08fd97968e725fea80a23d70835853acbe74648a052299b62a5e343820b36f0a76ecb3cb207d1443b47fc5d43154b40a7a0e39be518719f2c3ef589398
7
+ data.tar.gz: df4e987d43c13dd0d3866feefc4cfe2cf5b84c8519fb854d54e169f42ab0909b07890893498dd2e30635e36645630647db9451b2c32de737c345ac52b6ed3205
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 3.4.1 (2024-02-07)
2
+
3
+ - Added current stats to query details page
4
+ - Improved tune page for latest PgTune
5
+
6
+ ## 3.4.0 (2023-11-28)
7
+
8
+ - Added support for explaining normalized queries with Postgres 16
9
+ - Added Docker image for `linux/arm64`
10
+
1
11
  ## 3.3.4 (2023-09-05)
2
12
 
3
13
  - Fixed support for aliases in config file
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2023 Andrew Kane, 2008-2014 Heroku (initial queries)
1
+ Copyright (c) 2014-2024 Andrew Kane, 2008-2014 Heroku (initial queries)
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -8,7 +8,7 @@ A performance dashboard for Postgres
8
8
 
9
9
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
10
10
 
11
- [![Build Status](https://github.com/ankane/pghero/workflows/build/badge.svg?branch=master)](https://github.com/ankane/pghero/actions) [![Docker Pulls](https://img.shields.io/docker/pulls/ankane/pghero)](https://hub.docker.com/r/ankane/pghero)
11
+ [![Build Status](https://github.com/ankane/pghero/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/pghero/actions)
12
12
 
13
13
  ## Documentation
14
14
 
@@ -186,7 +186,7 @@ module PgHero
186
186
  @explainable_query = stats[:explainable_query]
187
187
 
188
188
  if @show_details
189
- query_hash_stats = @database.query_hash_stats(@query_hash, user: @user)
189
+ query_hash_stats = @database.query_hash_stats(@query_hash, user: @user, current: true)
190
190
 
191
191
  @chart_data = [{name: "Value", data: query_hash_stats.map { |r| [r[:captured_at].change(sec: 0), (r[:total_minutes] * 60 * 1000).round] }, library: chart_library_options}]
192
192
  @chart2_data = [{name: "Value", data: query_hash_stats.map { |r| [r[:captured_at].change(sec: 0), r[:average_time].round(1)] }, library: chart_library_options}]
@@ -292,12 +292,14 @@ module PgHero
292
292
  # need to prevent CSRF and DoS
293
293
  if request.post? && @query.present?
294
294
  begin
295
+ generic_plan = @database.server_version_num >= 160000 && @query.include?("$1")
296
+
295
297
  explain_options =
296
298
  case params[:commit]
297
299
  when "Analyze"
298
300
  {analyze: true}
299
301
  when "Visualize"
300
- if @explain_analyze_enabled
302
+ if @explain_analyze_enabled && !generic_plan
301
303
  {analyze: true, costs: true, verbose: true, buffers: true, format: "json"}
302
304
  else
303
305
  {costs: true, verbose: true, format: "json"}
@@ -306,6 +308,8 @@ module PgHero
306
308
  {}
307
309
  end
308
310
 
311
+ explain_options[:generic_plan] = true if generic_plan
312
+
309
313
  if explain_options[:analyze] && !@explain_analyze_enabled
310
314
  render_text "Explain analyze not enabled", status: :bad_request
311
315
  return
@@ -319,8 +323,10 @@ module PgHero
319
323
  @error =
320
324
  if message == "Unsafe statement"
321
325
  "Unsafe statement"
322
- elsif message.start_with?("PG::ProtocolViolation: ERROR: bind message supplies 0 parameters")
326
+ elsif message.start_with?("PG::UndefinedParameter")
323
327
  "Can't explain queries with bind parameters"
328
+ elsif message.include?("EXPLAIN options ANALYZE and GENERIC_PLAN cannot be used together")
329
+ "Can't analyze queries with bind parameters"
324
330
  elsif message.start_with?("PG::SyntaxError")
325
331
  "Syntax error with query"
326
332
  elsif message.start_with?("PG::QueryCanceled")
@@ -12,7 +12,7 @@ module PgHero
12
12
  if (sql.sub(/;\z/, "").include?(";") || sql.upcase.include?("COMMIT")) && !explain_safe?
13
13
  raise ActiveRecord::StatementInvalid, "Unsafe statement"
14
14
  end
15
- explanation = select_all("EXPLAIN #{sql}").map { |v| v[:"QUERY PLAN"] }.join("\n")
15
+ explanation = execute("EXPLAIN #{sql}").map { |v| v["QUERY PLAN"] }.join("\n")
16
16
  end
17
17
 
18
18
  explanation
@@ -20,11 +20,12 @@ module PgHero
20
20
 
21
21
  # TODO rename to explain in 4.0
22
22
  # note: this method is not affected by the explain option
23
- def explain_v2(sql, analyze: nil, verbose: nil, costs: nil, settings: nil, buffers: nil, wal: nil, timing: nil, summary: nil, format: "text")
23
+ def explain_v2(sql, analyze: nil, verbose: nil, costs: nil, settings: nil, generic_plan: nil, buffers: nil, wal: nil, timing: nil, summary: nil, format: "text")
24
24
  options = []
25
25
  add_explain_option(options, "ANALYZE", analyze)
26
26
  add_explain_option(options, "VERBOSE", verbose)
27
27
  add_explain_option(options, "SETTINGS", settings)
28
+ add_explain_option(options, "GENERIC_PLAN", generic_plan)
28
29
  add_explain_option(options, "COSTS", costs)
29
30
  add_explain_option(options, "BUFFERS", buffers)
30
31
  add_explain_option(options, "WAL", wal)
@@ -172,11 +172,10 @@ module PgHero
172
172
  query_stats.select { |q| q[:calls].to_i >= slow_query_calls.to_i && q[:average_time].to_f >= slow_query_ms.to_f }
173
173
  end
174
174
 
175
- # TODO option to include current period
176
- def query_hash_stats(query_hash, user: nil)
175
+ def query_hash_stats(query_hash, user: nil, current: false)
177
176
  if historical_query_stats_enabled? && supports_query_hash?
178
177
  start_at = 24.hours.ago
179
- select_all_stats <<~SQL
178
+ stats = select_all_stats <<~SQL
180
179
  SELECT
181
180
  captured_at,
182
181
  total_time / 1000 / 60 AS total_minutes,
@@ -193,6 +192,15 @@ module PgHero
193
192
  ORDER BY
194
193
  1 ASC
195
194
  SQL
195
+ if current
196
+ captured_at = Time.current
197
+ current_stats = current_query_stats(query_hash: query_hash, user: user, origin: true)
198
+ current_stats.each do |r|
199
+ r[:captured_at] = captured_at
200
+ end
201
+ stats += current_stats
202
+ end
203
+ stats
196
204
  else
197
205
  raise NotEnabled, "Query hash stats not enabled"
198
206
  end
@@ -201,7 +209,7 @@ module PgHero
201
209
  private
202
210
 
203
211
  # http://www.craigkerstiens.com/2013/01/10/more-on-postgres-performance/
204
- def current_query_stats(limit: nil, sort: nil, database: nil, query_hash: nil)
212
+ def current_query_stats(limit: nil, sort: nil, database: nil, query_hash: nil, user: nil, origin: false)
205
213
  if query_stats_enabled?
206
214
  limit ||= 100
207
215
  sort ||= "total_minutes"
@@ -225,10 +233,12 @@ module PgHero
225
233
  calls > 0 AND
226
234
  pg_database.datname = #{database ? quote(database) : "current_database()"}
227
235
  #{query_hash ? "AND queryid = #{quote(query_hash)}" : nil}
236
+ #{user ? "AND rolname = #{quote(user)}" : nil}
228
237
  )
229
238
  SELECT
230
239
  query,
231
240
  query AS explainable_query,
241
+ #{origin ? "(SELECT regexp_matches(query, '.*/\\*(.+?)\\*/'))[1] AS origin," : nil}
232
242
  query_hash,
233
243
  query_stats.user,
234
244
  total_minutes,
@@ -319,7 +329,7 @@ module PgHero
319
329
  end
320
330
 
321
331
  def explainable?(query)
322
- query =~ /select/i && !query.include?("?)") && !query.include?("= ?") && !query.include?("$1") && query !~ /limit \?/i
332
+ query =~ /select/i && (server_version_num >= 160000 || (!query.include?("?)") && !query.include?("= ?") && !query.include?("$1") && query !~ /limit \?/i))
323
333
  end
324
334
 
325
335
  # removes comments
@@ -3,7 +3,14 @@ module PgHero
3
3
  module Settings
4
4
  def settings
5
5
  names =
6
- if server_version_num >= 90500
6
+ if server_version_num >= 100000
7
+ %i(
8
+ max_connections shared_buffers effective_cache_size maintenance_work_mem
9
+ checkpoint_completion_target wal_buffers default_statistics_target
10
+ random_page_cost effective_io_concurrency work_mem huge_pages
11
+ min_wal_size max_wal_size
12
+ )
13
+ elsif server_version_num >= 90500
7
14
  %i(
8
15
  max_connections shared_buffers effective_cache_size work_mem
9
16
  maintenance_work_mem min_wal_size max_wal_size checkpoint_completion_target
@@ -1,3 +1,3 @@
1
1
  module PgHero
2
- VERSION = "3.3.4"
2
+ VERSION = "3.4.1"
3
3
  end
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: 3.3.4
4
+ version: 3.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-05 00:00:00.000000000 Z
11
+ date: 2024-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  requirements: []
127
- rubygems_version: 3.4.10
127
+ rubygems_version: 3.5.3
128
128
  signing_key:
129
129
  specification_version: 4
130
130
  summary: A performance dashboard for Postgres