Class: Shiba::Explain::Checks
- Inherits:
-
Object
- Object
- Shiba::Explain::Checks
- Extended by:
- Shiba::Explain::CheckSupport::ClassMethods
- Includes:
- CheckSupport
- Defined in:
- lib/shiba/explain/checks.rb
Instance Attribute Summary collapse
-
#cost ⇒ Object
readonly
Returns the value of attribute cost.
Instance Method Summary collapse
- #add_message(tag, extra = {}) ⇒ Object
- #check_derived ⇒ Object
-
#check_index_walk ⇒ Object
check :check_index_walk disabling this one for now, it’s not quite good enough and has a high false-negative rate.
- #check_join ⇒ Object
- #check_key_size ⇒ Object
- #check_simple_table_scan ⇒ Object
-
#initialize(rows, index, stats, options, query, result) ⇒ Checks
constructor
A new instance of Checks.
- #run_checks! ⇒ Object
-
#simple_table_scan? ⇒ Boolean
TODO: need to parse SQL here I think.
- #table ⇒ Object
- #table_size ⇒ Object
- #tag_query_type ⇒ Object
Methods included from Shiba::Explain::CheckSupport::ClassMethods
Methods included from CheckSupport
Constructor Details
#initialize(rows, index, stats, options, query, result) ⇒ Checks
Returns a new instance of Checks.
9 10 11 12 13 14 15 16 17 18 |
# File 'lib/shiba/explain/checks.rb', line 9 def initialize(rows, index, stats, , query, result) @rows = rows @row = rows[index] @index = index @stats = stats @options = @query = query @result = result @tbl_message = {} end |
Instance Attribute Details
#cost ⇒ Object (readonly)
Returns the value of attribute cost.
20 21 22 |
# File 'lib/shiba/explain/checks.rb', line 20 def cost @cost end |
Instance Method Details
#add_message(tag, extra = {}) ⇒ Object
30 31 32 |
# File 'lib/shiba/explain/checks.rb', line 30 def (tag, extra = {}) @result. << { tag: tag, table_size: table_size, table: table }.merge(extra) end |
#check_derived ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/shiba/explain/checks.rb', line 55 def check_derived if table =~ /<derived.*?>/ # select count(*) from ( select 1 from foo where blah ) ('derived_table', size: nil) @cost = 0 end end |
#check_index_walk ⇒ Object
check :check_index_walk disabling this one for now, it’s not quite good enough and has a high false-negative rate.
90 91 92 93 94 95 |
# File 'lib/shiba/explain/checks.rb', line 90 def check_index_walk if first['index_walk'] @cost = limit ("index_walk") end end |
#check_join ⇒ Object
77 78 79 80 81 82 83 84 85 |
# File 'lib/shiba/explain/checks.rb', line 77 def check_join if @row['join_ref'] @access_type.sub!("access_type", "join_type") # TODO MAYBE: are multiple-table joins possible? or does it just ref one table? ref = @row['join_ref'].find { |r| r != 'const' } table = ref.split('.')[1] @tbl_message['join_to'] = table end end |
#check_key_size ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/shiba/explain/checks.rb', line 98 def check_key_size if @access_type == "access_type_index" # access-type index means a table-scan as performed on an index... all rows. key_size = table_size elsif @row['key'] key_size = @stats.estimate_key(table, @row['key'], @row['used_key_parts']) else key_size = table_size end # TBD: this appears to come from a couple of bugs. # one is we're not handling mysql index-merges, the other is that # we're not handling mysql table aliasing. if key_size.nil? key_size = 1 end if @row['join_ref'] # when joining, we'll say we read "key_size * (previous result size)" rows -- but up to # a max of the table size. I'm not sure this assumption is *exactly* # true but it feels good enough to start; a decent hash join should # nullify the cost of re-reading rows. I think. rows_read = [@result.result_size * key_size, table_size || 2**32].min # poke holes in this. Is this even remotely accurate? # We're saying that if we join to a a table with 100 rows per item # in the index, for each row we'll be joining in 100 more rows. Is that true? @result.result_size *= key_size else rows_read = key_size @result.result_size += key_size end @cost = Shiba::Explain::COST_PER_ROW_READ * rows_read # pin fully missed indexes to a 'low' threshold if @access_type == 'access_type_tablescan' @cost = [0.01, @cost].max end @result.cost += @cost @tbl_message['cost'] = @cost @tbl_message['rows_read'] = rows_read @tbl_message['index'] = @row['key'] @tbl_message['index_used'] = @row['used_key_parts'] (@access_type, @tbl_message) end |
#check_simple_table_scan ⇒ Object
45 46 47 48 49 50 51 |
# File 'lib/shiba/explain/checks.rb', line 45 def check_simple_table_scan if simple_table_scan? rows_read = [@query.limit, table_size].min @cost = @result.cost = rows_read * Shiba::Explain::COST_PER_ROW_READ @result. << { tag: 'limited_scan', cost: @result.cost, table: table, rows_read: rows_read } end end |
#run_checks! ⇒ Object
147 148 149 150 151 |
# File 'lib/shiba/explain/checks.rb', line 147 def run_checks! _run_checks! do :stop if @cost end end |
#simple_table_scan? ⇒ Boolean
TODO: need to parse SQL here I think
35 36 37 38 39 40 |
# File 'lib/shiba/explain/checks.rb', line 35 def simple_table_scan? @rows.size == 1 && (@row['using_index'] || !(@query.sql =~ /\s+WHERE\s+/i)) && (@row['access_type'] == "index" || (@query.sql !~ /order by/i)) && @query.limit end |
#table ⇒ Object
22 23 24 |
# File 'lib/shiba/explain/checks.rb', line 22 def table @row['table'] end |
#table_size ⇒ Object
26 27 28 |
# File 'lib/shiba/explain/checks.rb', line 26 def table_size @stats.table_count(table) end |
#tag_query_type ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/shiba/explain/checks.rb', line 64 def tag_query_type @access_type = @row['access_type'] if @access_type.nil? @cost = 0 return end @access_type = 'tablescan' if @access_type == 'ALL' @access_type = "access_type_" + @access_type end |