Class: AwesomeExplain::Insights::ActiveRecordInsights

Inherits:
Object
  • Object
show all
Defined in:
lib/awesome_explain/insights/active_record_insights.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#active_record_subscriberObject

Returns the value of attribute active_record_subscriber.



3
4
5
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 3

def active_record_subscriber
  @active_record_subscriber
end

#optionsObject

Returns the value of attribute options.



3
4
5
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 3

def options
  @options
end

Class Method Details

.analyze(options, &block) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 5

def self.analyze(options, &block)
  instance = new
  instance.init
  instance.options = options
  block_result = instance.instance_eval(&block)
  instance.tear_down
  block_result
end

Instance Method Details

#indexesObject



112
113
114
115
116
117
118
119
120
121
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 112

def indexes
  stats = SqlPlansInsights.plans_stats.map do |ps|
    ps.index_stats if ps.index_stats.size.positive?
  end.compact

  stats.inject(Hash.new(0)) do |h, s|
    h[s.keys.first] += s[s.keys.first].dig(:count)
    h
  end&.map {|s| "#{s.first} (#{s.last})"}&.join("\n")
end

#initObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 14

def init
  subscribed = ::ActiveRecord::LogSubscriber.log_subscribers.select do |s|
    s.is_a?(::AwesomeExplain::Subscribers::ActiveRecordPassiveSubscriber)
  end.size.positive?

  unless subscribed
    SqlPlansInsights.clear
    ::AwesomeExplain::Subscribers::ActiveRecordPassiveSubscriber.attach_to(
      :active_record
    )
  end

  Thread.current['ae_analyze'] = true
  Thread.current['ae_source'] = 'console'
end

#node_typesObject



103
104
105
106
107
108
109
110
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 103

def node_types
  SqlPlansInsights.plans_stats.map do |ps|
    ps.node_type_stats
  end.inject(Hash.new(0)) do |h, s|
    h[s.keys.first] += s[s.keys.first].dig(:count)
    h
  end&.map {|s| "#{s.first} (#{s.last})"}&.join("\n")
end

Returns:

  • (Boolean)


30
31
32
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 30

def print_sql?
  options.dig(:print) == true
end

#seq_scansObject



88
89
90
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 88

def seq_scans
  SqlPlansInsights.plans_stats.sum { |ps| ps.seq_scans }
end

#seq_scans_rowObject



130
131
132
133
134
135
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 130

def seq_scans_row
  color = seq_scans >= 1 ? :cyan : :green
  title = AwesomeExplain::Utils::Color.fg_color color, 'Seq Scans'
  value = AwesomeExplain::Utils::Color.fg_color color, seq_scans.to_s
  [title, value]
end

#tablesObject



92
93
94
95
96
97
98
99
100
101
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 92

def tables
  stats = SqlPlansInsights.plans_stats.map do |ps|
    ps.table_stats if ps.table_stats.size.positive?
  end.compact

  stats.inject(Hash.new(0)) do |h, s|
    h[s.keys.first] += s[s.keys.first].dig(:count)
    h
  end&.map {|s| "#{s.first} (#{s.last})"}&.join("\n")
end

#tear_downObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 34

def tear_down
  if SqlPlansInsights.plans_stats.size.positive?
    SqlPlansInsights.queries.each do |query|
      puts query
    end if print_sql?

    table = Terminal::Table.new do |t|
      t << ['Time (sec)', total_time]
      t << :separator
      t << ['Total Rows Planned', total_rows_planned]
      t << :separator
      t << ['Total Rows', total_rows]
      t << :separator
      t << total_loops_row
      t << :separator
      t << seq_scans_row
      t << :separator
      t << ['Tables', tables]
      t << :separator
      t << ['Node Types', node_types]
      t << :separator
      t << ['Indexes', indexes]
    end
    puts table
  end
  SqlPlansInsights.clear
  Thread.current['ae_analyze'] = false
  Thread.current['ae_source'] = nil
end

#total_loopsObject



84
85
86
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 84

def total_loops
  SqlPlansInsights.plans_stats.sum { |ps| ps.total_loops }
end

#total_loops_rowObject



123
124
125
126
127
128
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 123

def total_loops_row
  color = total_loops >= 100 ? :red : :green
  title = AwesomeExplain::Utils::Color.fg_color color, 'Total Loops'
  value = AwesomeExplain::Utils::Color.fg_color color, total_loops.to_s
  [title, value]
end

#total_rowsObject



80
81
82
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 80

def total_rows
  SqlPlansInsights.plans_stats.sum { |ps| ps.total_rows }
end

#total_rows_plannedObject



76
77
78
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 76

def total_rows_planned
  SqlPlansInsights.plans_stats.sum { |ps| ps.total_rows_planned }
end

#total_timeObject



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/awesome_explain/insights/active_record_insights.rb', line 64

def total_time
  stats = SqlPlansInsights.plans_stats.map do |ps|
    ps.table_stats if ps.table_stats.size.positive?
  end.compact

  time = stats.sum do |table_stat|
    table_stat.values.first.dig(:time)
  end

  (time / 1000).round(3)
end