shiba 0.9.1 → 0.9.2

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: e7eada3a6681422e90d6dc44bf19121abb12986defaabeb31ca779ed4cb0418a
4
- data.tar.gz: e0e38dbc12379a611b621eec501c677860721945833cd4248c22e53f0d1f203c
3
+ metadata.gz: 12302c0e4fc56d8c8fc0d14dc6e10a5ae84aeaac2c328937b78b9e14b8122faa
4
+ data.tar.gz: d0ae437286d3c4975630c5dab8dc5aa109eb38f3ed0f6e606cded20a1201b09f
5
5
  SHA512:
6
- metadata.gz: cef76568f5300e5a57ecd8c53f247a889fb3e09f40b2e5c15572f31fc81a5923cde7de6a71407fc1fe6022d95e612b8f66775f982ddbf576303d7e06d23e44d9
7
- data.tar.gz: bd0b080bfafde25a487ad2e47ee44c96b26e4e7b762cdb9fb62473727b775dae80ec22205d6fe767ce493659ddaa7774ed183ead5f806583beea6d4cc850a1c9
6
+ metadata.gz: 92d5a42d2b68381a8f07025dec47e289d75c642a2d53823658966c8032e0e1f2a826f6285b1834747dda798fa25968f27f05c00029f60345303dddc9e2b20c2a
7
+ data.tar.gz: f4911585fe1a38695b587e11b908265d480523b6e2fcb8966780d80f34ab9612c1a798f612f0a3262f77349d5686a27f4c3da3886824753b36021354c33b267e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shiba (0.9.1)
4
+ shiba (0.9.2)
5
5
  activesupport
6
6
 
7
7
  GEM
data/bin/explain CHANGED
@@ -42,7 +42,7 @@ file = $stdin if file.nil?
42
42
 
43
43
  if options["verbose"]
44
44
  $stderr.puts "Reading queries from '#{file.inspect}'..."
45
- $stderr.puts "Analyzing SQL to '#{json.inspect}'..."
45
+ $stderr.puts "Analyzing SQL to '#{options["json"].inspect}'..."
46
46
  end
47
47
 
48
48
  table_stats = Shiba::TableStats.new(Shiba.index_config, Shiba.connection, {})
@@ -39,7 +39,7 @@ module Shiba
39
39
  {
40
40
  'host' => c[:host],
41
41
  'database' => c[:database],
42
- 'user' => c[:username],
42
+ 'username' => c[:username],
43
43
  'password' => c[:password],
44
44
  'port' => c[:port],
45
45
  'server' => c[:server],
@@ -72,16 +72,28 @@ module Shiba
72
72
  def self.when_done
73
73
  return false if @done_hook
74
74
 
75
- case
76
- when defined?(Minitest.after_run)
77
- MiniTest.after_run { yield }
75
+ # define both minitest and rspec hooks -- it can be
76
+ # unclear in some envs which one is active. maybe even both could run in one process? not sure.
77
+ @shiba_done = false
78
+ if defined?(Minitest.after_run)
79
+ MiniTest.after_run do
80
+ yield unless @shiba_done
81
+ @shiba_done = true
82
+ end
78
83
  @done_hook = :minitest
79
- when defined?(RSpec.configure)
84
+ end
85
+
86
+ if defined?(RSpec.configure)
80
87
  RSpec.configure do |config|
81
- config.after(:suite) { yield }
88
+ config.after(:suite) do
89
+ yield unless @shiba_done
90
+ @shiba_done = true
91
+ end
82
92
  end
83
93
  @done_hook = :rspec
84
- else
94
+ end
95
+
96
+ if !@done_hook
85
97
  $stderr.puts "Warning: shiba could not find Minitest or RSpec."
86
98
  $stderr.puts "If tests are running with one of these libraries, ensure shiba is required after them."
87
99
  at_exit { yield }
data/lib/shiba/console.rb CHANGED
@@ -7,9 +7,7 @@ require 'shiba/reviewer'
7
7
 
8
8
  module Shiba
9
9
  # Provides a 'shiba' command to analyze queries from the console.
10
- # If required in IRB or Pry, the shiba command will automatically be available,
11
- # as it's injected into those consoles at the bottom of this file.
12
- #
10
+ # If required in IRB or Pry, the 'shiba' command will become available.
13
11
  # Example:
14
12
  # require 'shiba/console'
15
13
  #
data/lib/shiba/explain.rb CHANGED
@@ -48,6 +48,7 @@ module Shiba
48
48
  table: @query.from_table,
49
49
  md5: @query.md5,
50
50
  messages: @result.messages,
51
+ global: global,
51
52
  cost: @result.cost,
52
53
  severity: severity,
53
54
  raw_explain: humanized_explain,
@@ -55,6 +56,12 @@ module Shiba
55
56
  }
56
57
  end
57
58
 
59
+ def global
60
+ {
61
+ server: Shiba.connection.mysql? ? 'mysql' : 'postgres'
62
+ }
63
+ end
64
+
58
65
  def messages
59
66
  @result.messages
60
67
  end
@@ -15,14 +15,14 @@ module Shiba
15
15
 
16
16
  Table = Struct.new(:name, :count, :indexes) do
17
17
  def encode_with(coder)
18
- coder.map = self.to_h.stringify_keys
19
- coder.map.delete('name')
20
-
21
18
  if self.count.nil?
22
19
  #uuuugly. No unique keys. we'll take our best guess.
23
20
  self.count = indexes.map { |i, parts| parts.columns.map { |v| v.raw_cardinality } }.flatten.max
24
21
  end
25
22
 
23
+ coder.map = self.to_h.stringify_keys
24
+ coder.map.delete('name')
25
+
26
26
  coder.map['column_sizes'] = column_sizes
27
27
  coder.tag = nil
28
28
  end
@@ -110,7 +110,7 @@ module Shiba
110
110
  ratio_threshold = 0.1
111
111
  elsif count <= 1_000_000
112
112
  ratio_threshold = 0.01
113
- elsif count <= 1_000_000_000
113
+ else
114
114
  ratio_threshold = 0.001
115
115
  end
116
116
 
@@ -165,9 +165,13 @@ module Shiba
165
165
  end
166
166
 
167
167
  def set_column_size(table_name, column, size)
168
- table = @tables[table_name]
169
- raise "couldn't find table: #{table_name}" unless table
168
+ if !@tables[table_name]
169
+ # we get here when a table has no indices. Should really do something smarter long term,
170
+ # as we'll have zero-counts, stuff like that.
171
+ build_table(table_name)
172
+ end
170
173
 
174
+ table = @tables[table_name]
171
175
  table.column_sizes[column] = size
172
176
  end
173
177
 
@@ -15,12 +15,12 @@ possible_key_check:
15
15
  key possible. Sometimes "possible_keys" will be inaccurate and no keys were possible.
16
16
  access_type_const:
17
17
  title: One row
18
- summary: The database only needs to read a single row from <b>{{table}}</b>.
18
+ summary: "{{ server }} reads one row from <b>{{table}}</b>."
19
19
  description: |
20
20
  This query selects at *most* one row, which is about as good as things get.
21
21
  access_type_ref:
22
22
  title: Index Scan
23
- summary: The database reads {{ formatted_cost }} rows in <b>{{ table }}</b> via the <i>{{ index }}</i> index ({{ key_parts }}).
23
+ summary: "{{ server }} reads {{ formatted_cost }} rows from <b>{{ table }}</b> via <i>{{ index }}</i> ({{ key_parts }})."
24
24
  description: |
25
25
  This query uses an index to find rows that match a single value. Often this
26
26
  has very good performance, but it depends on how many rows match that value.
@@ -31,8 +31,8 @@ join_type_ref:
31
31
  title: Indexed Join
32
32
  summary: <b>{{ table }}</b> is joined to <b>{{ join_to }}</b> via <i>{{ index }}</i>, reading {{ formatted_cost }} rows per joined item.
33
33
  access_type_range:
34
- title: Indexed
35
- summary: The database uses a "range scan" to read more than {{ formatted_cost }} rows in {{ table }} via the <b>{{ index }}</b> index ({{ key_parts }})
34
+ title: Range Scan
35
+ summary: "{{ server }} reads more than {{ formatted_cost }} rows from {{ table }} via <i>{{ index }}</i> ({{ key_parts }})"
36
36
  description: |
37
37
  This query uses an index to find rows that match a range of values, for instance
38
38
  `WHERE indexed_value in (1,2,5,6)` or `WHERE indexed_value >= 5 AND indexed_value <= 15`.
@@ -40,10 +40,10 @@ access_type_range:
40
40
  upped the formatted_cost of this query.
41
41
  access_type_index:
42
42
  title: Index Scan
43
- summary: The database reads {{ formatted_cost }} of the rows in <b>{{ table }}</b> via <i>{{ index }}</i>
43
+ summary: "{{ server }} reads {{ formatted_cost }} of the rows in <b>{{ table }}</b> via <i>{{ index }}</i>"
44
44
  access_type_tablescan:
45
45
  title: Table Scan
46
- summary: The database reads {{ formatted_cost }} of the rows in <b>{{ table }}</b>, skipping any indexes.
46
+ summary: "{{ server }} reads {{ formatted_cost }} of the rows in <b>{{ table }}</b>, skipping any indexes."
47
47
  description: |
48
48
  This query doesn't use any indexes to find data, meaning this query will need to evaluate
49
49
  every single row in the table. This is about the worst of all possible worlds.
@@ -53,7 +53,7 @@ access_type_tablescan:
53
53
  a world of pain.
54
54
  limited_scan:
55
55
  title: Limited Scan
56
- summary: The database reads {{ formatted_cost }} rows from {{ table }}.
56
+ summary: "{{ server }} reads {{ formatted_cost }} rows from {{ table }}."
57
57
  description: |
58
58
  This query doesn't use any indexes to find data, but since it doesn't care about
59
59
  ordering and it doesn't have any conditions, it only ever reads {{ formatted_cost }} rows.
@@ -71,4 +71,4 @@ index_walk:
71
71
  level: success
72
72
  retsize:
73
73
  title: Results
74
- summary: The database returns {{ formatted_result }} to the client.
74
+ summary: "{{ server }} returns {{ formatted_result }} to the client."
@@ -67,6 +67,7 @@ module Shiba
67
67
  begin
68
68
  explains = explain_file.each_line.map { |json| JSON.parse(json) }
69
69
  bad = explains.select { |explain| explain["severity"] && explain["severity"] != 'none' }
70
+ bad = bad.sort_by { |explain| explain["cost"] }
70
71
  bad.map { |explain| [ "#{explain["sql"]}:-2", explain ] }
71
72
  rescue Interrupt
72
73
  @err.puts "SIGINT: Canceled reading from STDIN. To read from an explain log, provide the --file option."
@@ -16,13 +16,15 @@ module Shiba
16
16
  explain["messages"].each do |message|
17
17
  tag = message['tag']
18
18
  data = present(message)
19
+ data.merge!(explain["global"])
20
+ body << " * "
19
21
  body << @templates[tag]["title"]
20
22
  body << ": "
21
23
  body << render_template(@templates[tag]["summary"], data)
22
24
  body << "\n"
23
25
  end
24
26
 
25
- body << "Estimated query time: %.2fs" % explain['cost']
27
+ body << " * Estimated query time: %.2fs" % explain['cost']
26
28
  body
27
29
  end
28
30
 
data/lib/shiba/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Shiba
2
- VERSION = "0.9.1"
2
+ VERSION = "0.9.2"
3
3
  end
data/web/src/App.vue CHANGED
@@ -34,7 +34,7 @@
34
34
  </div>
35
35
  <a name="lowExapnded"></a>
36
36
  <div class="queries" v-if="lowExpanded">
37
- <query v-for="query in queriesLow" v-bind:query="query" v-bind:key="query.sql" v-bind:tags="tags" v-bind:url="url"></query>
37
+ <query v-for="query in queriesLow" v-bind:query="query" v-bind:key="query.sql" v-bind:tags="tags" v-bind:url="url" v-bind:global="global"></query>
38
38
  </div>
39
39
  </div>
40
40
  <div style="height:50px"></div>
@@ -90,6 +90,7 @@ export default {
90
90
  highQ: [],
91
91
  lowQ: [],
92
92
  tags: {},
93
+ global: {},
93
94
  lowExpanded: false,
94
95
  hasFuzzed: false,
95
96
  search: '',
@@ -112,6 +113,7 @@ export default {
112
113
  setupData: function(data) {
113
114
  this.url = data.url;
114
115
  this.tags = data.tags;
116
+ this.global = data.global;
115
117
 
116
118
  Object.keys(this.tags).forEach((k) => {
117
119
  registerMessage(k, this.tags[k].title, this.tags[k].summary);
@@ -94,7 +94,7 @@ export default function (tag, title, summary) {
94
94
 
95
95
  Vue.component(`tag-${tag}`, {
96
96
  template: tmpl,
97
- props: [ 'table_size', 'result_size', 'table', 'cost', 'index', 'join_to', 'index_used', 'running_cost', 'tables', 'rows_read', 'result_bytes' ],
97
+ props: [ 'table_size', 'result_size', 'table', 'cost', 'index', 'join_to', 'index_used', 'running_cost', 'tables', 'rows_read', 'result_bytes', 'server' ],
98
98
  computed: templateComputedFunctions,
99
99
  data: function () {
100
100
  return { lastRunnningCost: undefined };
@@ -19,7 +19,7 @@
19
19
  <backtrace v-bind:backtrace="query.backtrace" v-bind:url="url"></backtrace>
20
20
  </div>
21
21
  <table class="shiba-messages">
22
- <component v-for="message in query.messages" v-bind:is="'tag-' + message.tag" v-bind="message" v-bind:key="query.md5 + ':' + message.tag"></component>
22
+ <component v-for="message in messages" v-bind:is="'tag-' + message.tag" v-bind="message" v-bind:key="query.md5 + ':' + message.tag"></component>
23
23
  </table>
24
24
  <div v-if="debug" style="font-size: 10px">md5: {{ query.md5 }}</div>
25
25
  <div v-if="!rawExpanded">
@@ -42,7 +42,7 @@
42
42
  export default {
43
43
  name: 'Query',
44
44
  template: '#query-template',
45
- props: ['query', 'tags', 'url', 'debug'],
45
+ props: ['query', 'tags', 'url', 'debug', 'global'],
46
46
  data: function () {
47
47
  return {
48
48
  expanded: false,
@@ -95,6 +95,12 @@
95
95
  },
96
96
  },
97
97
  computed: {
98
+ messages: function () {
99
+ var array = this.query.messages.map((m) =>
100
+ Object.assign({}, { server: 'MySQL' }, m)
101
+ );
102
+ return array;
103
+ },
98
104
  expandText: function() {
99
105
  return this.expanded ? "-" : "+";
100
106
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shiba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Osheroff
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-03-19 00:00:00.000000000 Z
12
+ date: 2019-03-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -159,8 +159,8 @@ files:
159
159
  - web/babel.config.js
160
160
  - web/dist/example_data.json
161
161
  - web/dist/index.html
162
- - web/dist/js/app.2ba8a5da.js
163
- - web/dist/js/app.2ba8a5da.js.map
162
+ - web/dist/js/app.91a7529a.js
163
+ - web/dist/js/app.91a7529a.js.map
164
164
  - web/package-lock.json
165
165
  - web/package.json
166
166
  - web/public/index.html