lookout-query_reviewer 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +136 -0
  3. data/Rakefile +24 -0
  4. data/lib/query_reviewer.rb +66 -0
  5. data/lib/query_reviewer/array_extensions.rb +29 -0
  6. data/lib/query_reviewer/controller_extensions.rb +67 -0
  7. data/lib/query_reviewer/mysql_adapter_extensions.rb +92 -0
  8. data/lib/query_reviewer/mysql_analyzer.rb +62 -0
  9. data/lib/query_reviewer/query_warning.rb +17 -0
  10. data/lib/query_reviewer/rails.rb +37 -0
  11. data/lib/query_reviewer/sql_query.rb +131 -0
  12. data/lib/query_reviewer/sql_query_collection.rb +103 -0
  13. data/lib/query_reviewer/sql_sub_query.rb +45 -0
  14. data/lib/query_reviewer/tasks.rb +8 -0
  15. data/lib/query_reviewer/views/_box.html.erb +11 -0
  16. data/lib/query_reviewer/views/_box_ajax.js +34 -0
  17. data/lib/query_reviewer/views/_box_body.html.erb +73 -0
  18. data/lib/query_reviewer/views/_box_disabled.html.erb +2 -0
  19. data/lib/query_reviewer/views/_box_header.html.erb +1 -0
  20. data/lib/query_reviewer/views/_box_includes.html.erb +234 -0
  21. data/lib/query_reviewer/views/_explain.html.erb +30 -0
  22. data/lib/query_reviewer/views/_js_includes.html.erb +68 -0
  23. data/lib/query_reviewer/views/_js_includes_new.html.erb +68 -0
  24. data/lib/query_reviewer/views/_profile.html.erb +26 -0
  25. data/lib/query_reviewer/views/_query_sql.html.erb +8 -0
  26. data/lib/query_reviewer/views/_query_trace.html.erb +31 -0
  27. data/lib/query_reviewer/views/_query_with_warning.html.erb +54 -0
  28. data/lib/query_reviewer/views/_spectrum.html.erb +10 -0
  29. data/lib/query_reviewer/views/_warning_no_query.html.erb +8 -0
  30. data/lib/query_reviewer/views/query_review_box_helper.rb +99 -0
  31. data/query_reviewer_defaults.yml +39 -0
  32. metadata +77 -0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,136 @@
1
+ # QueryReviewer #
2
+
3
+ ## Introduction ##
4
+
5
+ QueryReviewer is an advanced SQL query analyzer. It accomplishes the following goals:
6
+
7
+ * View all EXPLAIN output for all SELECT queries to generate a page
8
+ * Rate a page's SQL usage into one of three categories: OK, WARNING, CRITICAL
9
+ * Attach meaningful warnings to individual queries, and collections of queries
10
+ * Display interactive summary on page
11
+
12
+ ## Use This Fork ##
13
+
14
+ I use this utility for most of my MySQL-backed Rails projects. Still the best out there in my opinion for analyzing and understanding your generated SQL queries.
15
+ I forked the original [query_reviewer](https://github.com/dsboulder/query_reviewer) and applied a collection of patches that have been made since the plugin was created.
16
+ A list of the biggest additions below:
17
+
18
+ * Snazzed up the README into markdown for better readability
19
+ * Full compatibility for Rails 3 (including Railtie)
20
+ * Cleanup and move rake task to `lib/tasks` to fix deprecation warnings
21
+ * Added gemspec for use with Bundler (as a gem)
22
+ * Fixed missing tags and additional XHTML escaping
23
+ * Fix SQL escaping for better XHTML compatibility
24
+ * Fixes for deprecation warnings and for 1.9 compatiblity
25
+ * Converts templates to more modern foo.html.erb naming
26
+
27
+ As of August 2011, This has become the "official" version to use. David has deprecated the [original repo](https://github.com/dsboulder/query_reviewer) and recommends that people looking for this utility use this fork instead.
28
+ This fork compiles a variety of patches that were made since that time along with additional work to support compatibility with 1.9 and Rails 3.
29
+ **Also:** If anyone else creates generally useful enhancements to this utility please start by forking this and then issue me a pull request.
30
+
31
+ **Note:** This plugin should work for Rails 2.X and Rails 3. If you run into issues, please file a bug report or send a pull request. I consider this new fork to be a group effort
32
+ so if you want to be added as a contributor to help maintain this, please let me know!
33
+
34
+ ## Database Limitations ##
35
+
36
+ As of right now, this plugin supports analyzing queries **only for MySQL**. I consider this the primary **limitation** of this gem.
37
+ I am now using PostgreSQL for a number of my projects and the "EXPLAIN" output is totally different. Several people have started a PostgreSQL adapter for
38
+ this plugin, but none that are mature enough to include here.
39
+
40
+ If anyone is interested at taking a stab at implementing PostgreSQL support for this utility, that would be hugely appreciated! I hope this plugin can come to support
41
+ all the major Rails adapters over time.
42
+
43
+ ## Installation ##
44
+
45
+ All you have to do is install it into your Rails 2 or 3 project.
46
+
47
+ gem install query_reviewer
48
+
49
+ Right now if you use bundler, simply add this to your Gemfile:
50
+
51
+ # Gemfile
52
+ gem "query_reviewer", :git => "git://github.com/nesquena/query_reviewer.git"
53
+
54
+ If you are not using bundler, you might want to [start using it](http://gembundler.com/rails23.html). You can also install this as a plugin:
55
+
56
+ script/plugin install git://github.com/nesquena/query_reviewer.git
57
+
58
+ In Rails 2, the rake tasks are not loaded automatically (as a gem), you’ll need to add the following to your Rakefile:
59
+
60
+ # Rakefile
61
+ begin
62
+ require 'query_reviewer/tasks'
63
+ rescue LoadError
64
+ STDERR.puts "The query_reviewer gem could not be found!"
65
+ end
66
+
67
+ You can then run:
68
+
69
+ $ rake query_reviewer:setup
70
+
71
+ Which will create `config/query_reviewer.yml` in your application, see below for what these options mean.
72
+ If you don't create a config file, the gem will use the default in `vendor/plugins/query_reviewer`.
73
+
74
+ ## Configuration ##
75
+
76
+ The configuration file allows you to set configuration parameters shared across all rails environment, as well as overriding those shared parameteres with environment-specific parameters (such as disabling analysis on production!)
77
+
78
+ * `enabled`: whether any output or query analysis is performed. Set this false in production!
79
+ * `inject_view`: controls whether the output automatically is injected before the </body> in HTML output.
80
+ * `profiling`: when enabled, runs the MySQL SET PROFILING=1 for queries longer than the `warn_duration_threshold` / 2.0
81
+ * `production_data`: whether the duration of a query should be taken into account
82
+ * `stack_trace_lines`: number of lines of call stack to include in the "short" version of the stack trace
83
+ * `trace_includes_vendor`: whether the "short" version of the stack trace should include files in /vendor
84
+ * `trace_includes_lib`: whether the "short" version of the stack trace should include files in /lib
85
+ * `warn_severity`: the severity of problem that merits "WARNING" status
86
+ * `critical_severity`: the severity of problem that merits "CRITICAL" status
87
+ * `warn_query_count`: the number of queries in a single request that merits "WARNING" status
88
+ * `critical_query_count`: the number of queries in a single request that merits "CRITICAL" status
89
+ * `warn_duration_threshold`: how long a query must take in seconds (float) before it's considered "WARNING"
90
+ * `critical_duration_threshold`: how long a query must take in seconds (float) before it's considered "CRITICIAL"
91
+
92
+ ## Example ##
93
+
94
+ If you disable the inject_view option above, you'll need to manually put the analyzer's output into your view:
95
+
96
+ # view.html.haml
97
+ = query_review_output
98
+
99
+ and that will display the analyzer view!
100
+
101
+ ## Resources ##
102
+
103
+ Random collection of resources that might be interesting related to this utility:
104
+
105
+ * <http://blog.purifyapp.com/2010/06/15/optimise-your-mysql/>
106
+ * <http://www.tatvartha.com/2009/09/rails-optimizing-database-indexes-using-query_analyzer-and-query_reviewer/>
107
+ * <http://www.geekskillz.com/articles/using-indexes-to-improve-rails-performance>
108
+ * <http://www.williambharding.com/blog/rails/rails-mysql-indexes-step-1-in-pitiful-to-prime-performance/>
109
+ * <http://guides.rubyonrails.org/performance_testing.html>
110
+
111
+ Other related gems that prove useful for database optimization:
112
+
113
+ * [bullet](https://github.com/flyerhzm/bullet)
114
+ * [slim-scrooge](https://github.com/sdsykes/slim_scrooge)
115
+ * [slim-attributes](https://github.com/sdsykes/slim-attributes)
116
+
117
+ ## Alternatives ##
118
+
119
+ There have been other alternatives created since this was originally released. A few of the best are listed below. I for one still prefer this utility over the other options:
120
+
121
+ * [rack-bug](https://github.com/brynary/rack-bug)
122
+ * [rails-footnotes](https://github.com/josevalim/rails-footnotes)
123
+ * [newrelic-development](http://support.newrelic.com/kb/docs/developer-mode)
124
+ * [palmist](https://github.com/flyingmachine/palmist)
125
+ * [query_diet](https://github.com/makandra/query_diet)
126
+ * [query_trace](https://github.com/ntalbott/query_trace)
127
+
128
+ Know of a better alternative? Let me know!
129
+
130
+ ## Acknowledgements ##
131
+
132
+ Created by Kongregate & David Stevenson.
133
+ Refactorings and compilations of all fixes since was done by Nathan Esquenazi.
134
+ Also, ajvargo for helping with some fixes.
135
+
136
+ Copyright (c) 2007-2008 Kongregate & David Stevenson, released under the MIT license
@@ -0,0 +1,24 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'bundler'
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the query_reviewer plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the query_reviewer plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'QueryReviewer'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
@@ -0,0 +1,66 @@
1
+ # QueryReviewer
2
+ require "ostruct"
3
+ require 'erb'
4
+ require 'yaml'
5
+
6
+ module QueryReviewer
7
+ CONFIGURATION = {}
8
+
9
+ def self.load_configuration
10
+ default_config = YAML::load(ERB.new(IO.read(File.join(File.dirname(__FILE__), "..", "query_reviewer_defaults.yml"))).result)
11
+
12
+ CONFIGURATION.merge!(default_config["all"] || {})
13
+ CONFIGURATION.merge!(default_config[Rails.env || "test"] || {})
14
+
15
+ app_config_file = Rails.root + "config/query_reviewer.yml"
16
+
17
+ if app_config_file.exist?
18
+ app_config = YAML.load(ERB.new(IO.read(app_config_file)).result)
19
+ CONFIGURATION.merge!(app_config["all"] || {})
20
+ CONFIGURATION.merge!(app_config[Rails.env || "test"] || {})
21
+ end
22
+
23
+ if enabled?
24
+ begin
25
+ CONFIGURATION["uv"] ||= if Gem::Specification.respond_to?(:find_all_by_name)
26
+ !Gem::Specification.find_all_by_name('uv').empty?
27
+ else # RubyGems < 1.8.0
28
+ !Gem.searcher.find("uv").nil?
29
+ end
30
+
31
+ if CONFIGURATION["uv"]
32
+ require "uv"
33
+ end
34
+ rescue
35
+ CONFIGURATION["uv"] ||= false
36
+ end
37
+
38
+ require "query_reviewer/query_warning"
39
+ require "query_reviewer/array_extensions"
40
+ require "query_reviewer/sql_query"
41
+ require "query_reviewer/mysql_analyzer"
42
+ require "query_reviewer/sql_sub_query"
43
+ require "query_reviewer/mysql_adapter_extensions"
44
+ require "query_reviewer/controller_extensions"
45
+ require "query_reviewer/sql_query_collection"
46
+ end
47
+ end
48
+
49
+ def self.enabled?
50
+ CONFIGURATION["enabled"]
51
+ end
52
+
53
+ def self.safe_log(&block)
54
+ if @logger.nil?
55
+ yield
56
+ elsif @logger.respond_to?(:quietly)
57
+ @logger.quietly { yield }
58
+ elsif @logger.respond_to?(:silence)
59
+ @logger.silence { yield }
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ # Rails Integration
66
+ require 'query_reviewer/rails' if defined?(Rails)
@@ -0,0 +1,29 @@
1
+ module QueryReviewer
2
+ module ArrayExtensions #taken from query_analyser plugin
3
+ protected
4
+ def qa_columnized_row(fields, sized)
5
+ row = []
6
+ fields.each_with_index do |f, i|
7
+ row << sprintf("%0-#{sized[i]}s", f.to_s)
8
+ end
9
+ row.join(' | ')
10
+ end
11
+
12
+ public
13
+
14
+ def qa_columnized
15
+ sized = {}
16
+ self.each do |row|
17
+ row.values.each_with_index do |value, i|
18
+ sized[i] = [sized[i].to_i, row.keys[i].length, value.to_s.length].max
19
+ end
20
+ end
21
+
22
+ table = []
23
+ table << qa_columnized_row(self.first.keys, sized)
24
+ table << '-' * table.first.length
25
+ self.each { |row| table << qa_columnized_row(row.values, sized) }
26
+ table.join("\n ") # Spaces added to work with format_log_entry
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
1
+ require "action_view"
2
+ require File.join(File.dirname(__FILE__), "views", "query_review_box_helper")
3
+
4
+ module QueryReviewer
5
+ module ControllerExtensions
6
+ class QueryViewBase < ActionView::Base
7
+ include QueryReviewer::Views::QueryReviewBoxHelper
8
+ end
9
+
10
+ def self.included(base)
11
+ if QueryReviewer::CONFIGURATION["inject_view"]
12
+ alias_name = defined?(Rails::Railtie) ? :process_action : :perform_action
13
+ base.alias_method_chain(alias_name, :query_review)
14
+ end
15
+ base.alias_method_chain :process, :query_review
16
+ base.helper_method :query_review_output
17
+ end
18
+
19
+ def query_review_output(ajax = false, total_time = nil)
20
+ faux_view = QueryViewBase.new([File.join(File.dirname(__FILE__), "views")], {}, self)
21
+ queries = Thread.current["queries"]
22
+ queries.analyze!
23
+ faux_view.instance_variable_set("@queries", queries)
24
+ faux_view.instance_variable_set("@total_time", total_time)
25
+ if ajax
26
+ js = faux_view.render(:partial => "/box_ajax.js")
27
+ else
28
+ html = faux_view.render(:partial => "/box")
29
+ end
30
+ end
31
+
32
+ def add_query_output_to_view(total_time)
33
+ if request.xhr?
34
+ if cookies["query_review_enabled"]
35
+ if !response.content_type || response.content_type.include?("text/html")
36
+ response.body += "<script type=\"text/javascript\">"+query_review_output(true, total_time)+"</script>"
37
+ elsif response.content_type && response.content_type.include?("text/javascript")
38
+ response.body += ";\n"+query_review_output(true, total_time)
39
+ end
40
+ end
41
+ else
42
+ if response.body.is_a?(String) && response.body.match(/<\/body>/i)
43
+ idx = (response.body =~ /<\/body>/i)
44
+ html = query_review_output(false, total_time)
45
+ response.body = response.body.insert(idx, html)
46
+ end
47
+ end
48
+ end
49
+
50
+ def perform_action_with_query_review(*args)
51
+ return unless (CONFIGURATION["enabled"] == true and cookies["query_review_enabled"]) ||
52
+ (CONFIGURATION["enabled"] == "based_on_session" and session["query_review_enabled"])
53
+
54
+ t1 = Time.now
55
+ r = defined?(Rails::Railtie) ? process_action_without_query_review(*args) : perform_action_without_query_review(*args)
56
+ t2 = Time.now
57
+ add_query_output_to_view(t2 - t1)
58
+ r
59
+ end
60
+ alias_method :process_action_with_query_review, :perform_action_with_query_review
61
+
62
+ def process_with_query_review(*args) #:nodoc:
63
+ Thread.current["queries"] = SqlQueryCollection.new
64
+ process_without_query_review(*args)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,92 @@
1
+ module QueryReviewer
2
+ module MysqlAdapterExtensions
3
+ def self.included(base)
4
+ base.alias_method_chain :select, :review
5
+ base.alias_method_chain :update, :review
6
+ base.alias_method_chain :insert, :review
7
+ base.alias_method_chain :delete, :review
8
+ end
9
+
10
+ def update_with_review(sql, *args)
11
+ t1 = Time.now
12
+ result = update_without_review(sql, *args)
13
+ t2 = Time.now
14
+
15
+ create_or_add_query_to_query_reviewer!(sql, nil, t2 - t1, nil, "UPDATE", result)
16
+
17
+ result
18
+ end
19
+
20
+ def insert_with_review(sql, *args)
21
+ t1 = Time.now
22
+ result = insert_without_review(sql, *args)
23
+ t2 = Time.now
24
+
25
+ create_or_add_query_to_query_reviewer!(sql, nil, t2 - t1, nil, "INSERT")
26
+
27
+ result
28
+ end
29
+
30
+ def delete_with_review(sql, *args)
31
+ t1 = Time.now
32
+ result = delete_without_review(sql, *args)
33
+ t2 = Time.now
34
+
35
+ create_or_add_query_to_query_reviewer!(sql, nil, t2 - t1, nil, "DELETE", result)
36
+
37
+ result
38
+ end
39
+
40
+ def select_with_review(sql, *args)
41
+ return select_without_review(sql, *args) unless query_reviewer_enabled?
42
+
43
+ sql.gsub!(/^SELECT /i, "SELECT SQL_NO_CACHE ") if QueryReviewer::CONFIGURATION["disable_sql_cache"]
44
+ QueryReviewer.safe_log { execute("SET PROFILING=1") } if QueryReviewer::CONFIGURATION["profiling"]
45
+ t1 = Time.now
46
+ query_results = select_without_review(sql, *args)
47
+ t2 = Time.now
48
+
49
+ if @logger && sql =~ /^select/i && query_reviewer_enabled?
50
+ use_profiling = QueryReviewer::CONFIGURATION["profiling"]
51
+ use_profiling &&= (t2 - t1) >= QueryReviewer::CONFIGURATION["warn_duration_threshold"].to_f / 2.0 if QueryReviewer::CONFIGURATION["production_data"]
52
+
53
+ if use_profiling
54
+ t5 = Time.now
55
+ QueryReviewer.safe_log { execute("SET PROFILING=1") }
56
+ t3 = Time.now
57
+ select_without_review(sql, *args)
58
+ t4 = Time.now
59
+ profile = QueryReviewer.safe_log { select_without_review("SHOW PROFILE ALL", *args) }
60
+ QueryReviewer.safe_log { execute("SET PROFILING=0") }
61
+ t6 = Time.now
62
+ Thread.current["queries"].overhead_time += t6 - t5
63
+ else
64
+ profile = nil
65
+ end
66
+
67
+ cols = QueryReviewer.safe_log do
68
+ select_without_review("explain #{sql}", *args)
69
+ end
70
+
71
+ duration = t3 ? [t2 - t1, t4 - t3].min : t2 - t1
72
+ create_or_add_query_to_query_reviewer!(sql, cols, duration, profile)
73
+
74
+ #@logger.debug(format_log_entry("Analyzing #{name}\n", query.to_table)) if @logger.level <= Logger::INFO
75
+ end
76
+ query_results
77
+ end
78
+
79
+ def query_reviewer_enabled?
80
+ Thread.current["queries"] && Thread.current["queries"].respond_to?(:find_or_create_sql_query) && Thread.current["query_reviewer_enabled"]
81
+ end
82
+
83
+ def create_or_add_query_to_query_reviewer!(sql, cols, run_time, profile, command = "SELECT", affected_rows = 1)
84
+ if query_reviewer_enabled?
85
+ t1 = Time.now
86
+ Thread.current["queries"].find_or_create_sql_query(sql, cols, run_time, profile, command, affected_rows)
87
+ t2 = Time.now
88
+ Thread.current["queries"].overhead_time += t2 - t1
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,62 @@
1
+ module QueryReviewer
2
+ module MysqlAnalyzer
3
+ def do_mysql_analysis!
4
+ analyze_select_type!
5
+ analyze_query_type!
6
+ analyze_key!
7
+ analyze_extras!
8
+ analyze_keylen!
9
+ end
10
+
11
+ def analyze_select_type!
12
+ if select_type.match /uncacheable subquery/
13
+ warn(:severity => 10, :field => "select_type", :desc => "Subquery must be run once for EVERY row in main query")
14
+ elsif select_type.match /dependent/
15
+ warn(:severity => 2, :field => "select_type", :desc => "Dependent subqueries can not be executed while the main query is running")
16
+ end
17
+ end
18
+
19
+ def analyze_query_type!
20
+ case query_type
21
+ when "system", "const", "eq_ref" then
22
+ praise("Yay")
23
+ when "ref", "ref_or_null", "range", "index_merge" then
24
+ praise("Not bad eh...")
25
+ when "unique_subquery", "index_subquery" then
26
+ #NOT SURE
27
+ when "index" then
28
+ warn(:severity => 8, :field => "query_type", :desc => "Full index tree scan (slightly faster than a full table scan)") unless !extra.include?("using where")
29
+ when "all" then
30
+ warn(:severity => 9, :field => "query_type", :desc => "Full table scan") unless !extra.include?("using where")
31
+ end
32
+ end
33
+
34
+ def analyze_key!
35
+ if self.key == "const"
36
+ praise "Way to go!"
37
+ elsif self.key.blank? && !self.extra.include?("select tables optimized away")
38
+ warn :severity => 6, :field => "key", :desc => "No index was used here. In this case, that meant scanning #{self.rows} rows."
39
+ end
40
+ end
41
+
42
+ def analyze_extras!
43
+ if self.extra.match(/range checked for each record/)
44
+ warn :severity => 4, :problem => "Range checked for each record", :desc => "MySQL found no good index to use, but found that some of indexes might be used after column values from preceding tables are known"
45
+ end
46
+
47
+ if self.extra.match(/using filesort/)
48
+ warn :severity => 2, :problem => "Using filesort", :desc => "MySQL must do an extra pass to find out how to retrieve the rows in sorted order."
49
+ end
50
+
51
+ if self.extra.match(/using temporary/)
52
+ warn :severity => 10, :problem => "Using temporary table", :desc => "To resolve the query, MySQL needs to create a temporary table to hold the result."
53
+ end
54
+ end
55
+
56
+ def analyze_keylen!
57
+ if self.key_len && !self.key_len.to_i.nil? && (self.key_len.to_i > QueryReviewer::CONFIGURATION["max_safe_key_length"])
58
+ warn :severity => 4, :problem => "Long key length (#{self.key_len.to_i})", :desc => "The key used for the index was rather long, potentially affecting indices in memory"
59
+ end
60
+ end
61
+ end
62
+ end