Permalink
Browse files

Merge remote branch 'nesq/master'

Conflicts:
	lib/query_reviewer/views/_box_body.html.erb
	lib/query_reviewer/views/_box_includes.rhtml
  • Loading branch information...
dsboulder authored and David Stevenson committed Apr 7, 2011
2 parents 51ccc1f + 9de60e7 commit 8202e49a26710c8ef7a55288cce578a8663a04dd
Showing with 624 additions and 432 deletions.
  1. +3 −0 .gitignore
  2. +0 −51 README
  3. +122 −0 README.md
  4. +2 −0 Rakefile
  5. +1 −13 init.rb
  6. +25 −26 lib/query_reviewer.rb
  7. +12 −7 lib/query_reviewer/controller_extensions.rb
  8. +5 −5 lib/query_reviewer/mysql_analyzer.rb
  9. +37 −0 lib/query_reviewer/rails.rb
  10. +13 −13 lib/query_reviewer/sql_query.rb
  11. +2 −1 lib/query_reviewer/sql_sub_query.rb
  12. +8 −0 lib/query_reviewer/tasks.rb
  13. 0 lib/query_reviewer/views/{_box.rhtml → _box.html.erb}
  14. +3 −3 lib/query_reviewer/views/{_box_body.rhtml → _box_body.html.erb}
  15. 0 lib/query_reviewer/views/{_box_disabled.rhtml → _box_disabled.html.erb}
  16. 0 lib/query_reviewer/views/{_box_header.rhtml → _box_header.html.erb}
  17. +234 −0 lib/query_reviewer/views/_box_includes.html.erb
  18. +0 −297 lib/query_reviewer/views/_box_includes.rhtml
  19. 0 lib/query_reviewer/views/{_explain.rhtml → _explain.html.erb}
  20. +68 −0 lib/query_reviewer/views/_js_includes.html.erb
  21. +68 −0 lib/query_reviewer/views/_js_includes_new.html.erb
  22. 0 lib/query_reviewer/views/{_profile.rhtml → _profile.html.erb}
  23. 0 lib/query_reviewer/views/{_query_sql.rhtml → _query_sql.html.erb}
  24. +1 −1 lib/query_reviewer/views/{_query_trace.rhtml → _query_trace.html.erb}
  25. +3 −3 lib/query_reviewer/views/{_query_with_warning.rhtml → _query_with_warning.html.erb}
  26. 0 lib/query_reviewer/views/{_spectrum.rhtml → _spectrum.html.erb}
  27. 0 lib/query_reviewer/views/{_warning_no_query.rhtml → _warning_no_query.html.erb}
  28. +5 −4 lib/query_reviewer/views/query_review_box_helper.rb
  29. +10 −0 query_reviewer.gemspec
  30. +1 −0 rails/init.rb
  31. +0 −7 tasks/query_reviewer_tasks.rake
  32. +1 −1 test/test_helper.rb
View
@@ -0,0 +1,3 @@
+pkg/*
+*.gem
+.bundle
View
51 README
@@ -1,51 +0,0 @@
-QueryReviewer
-=============
-
-QueryReviewer is an advanced SQL query analyzer. It accomplishes the following goals:
-
- * View all EXPLAIN output for all SELECT queries to generate a page (and optionally SHOW PROFILE ALL)
- * Rate a page's SQL usage into one of three categories: OK, WARNING, CRITICAL
- * Attach meaningful warnings to individual queries, and collections of queries
- * Display interactive summary on page
-
-All you have to do is install it. You can optionally run:
- rake query_reviewer:setup
-
-Which will create config/query_reviewer.yml, see below for what these options mean. If you don't have a config file,
-the plugin will use the default in vendor/plugins/query_reviewer.
-
-
-Configuration
-=============
-
-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!)
-
- * enabled: whether any output or query analysis is performed. Set this false in production!
- * inject_view: controls whether the output automatically is injected before the </body> in HTML output.
- * profiling: when enabled, runs the MySQL SET PROFILING=1 for queries longer than the warn_duration_threshold / 2.0
- * production_data: whether the duration of a query should be taken into account (if you don't have real data, don't let query duration effect you!)
-
- * stack_trace_lines: number of lines of call stack to include in the "short" version of the stack trace
- * trace_includes_vendor: whether the "short" verison of the stack trace should include files in /vendor
- * trace_includes_lib: whether the "short" verison of the stack trace should include files in /lib
-
- * warn_severity: the severity of problem that merits "WARNING" status
- * critical_severity: the severity of problem that merits "CRITICAL" status
-
- * warn_query_count: the number of queries in a single request that merits "WARNING" status
- * critical_query_count: the number of queries in a single request that merits "CRITICAL" status
-
- * warn_duration_threshold: how long a query must take in seconds (float) before it's considered "WARNING"
- * critical_duration_threshold: how long a query must take in seconds (float) before it's considered "CRITICIAL"
-
-
-Example
-=======
-
-If you disable the inject_view option, you'll need to manually put the analyzer's output into your view:
-
-<%= query_review_output %>
-
-
-Copyright (c) 2007-2008 Kongregate & David Stevenson, released under the MIT license
View
122 README.md
@@ -0,0 +1,122 @@
+# QueryReviewer #
+
+## Introduction ##
+
+QueryReviewer is an advanced SQL query analyzer. It accomplishes the following goals:
+
+ * View all EXPLAIN output for all SELECT queries to generate a page
+ * Rate a page's SQL usage into one of three categories: OK, WARNING, CRITICAL
+ * Attach meaningful warnings to individual queries, and collections of queries
+ * Display interactive summary on page
+
+## This Fork ##
+
+I use this utility for most of my rails projects. Still the best out there in my opinion for analyzing and understanding your generated SQL queries. 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. A list of the biggest additions below:
+
+ * Snazzed up the README into markdown for better readability
+ * Full compatibility for Rails 3 (including Railtie)
+ * Cleanup and move rake task to `lib/tasks` to fix deprecation warnings
+ * Added gemspec for use with Bundler (as a gem)
+ * Fixed missing tags and additional XHTML escaping
+ * Fix SQL escaping for better XHTML compatibility
+ * Fixes for deprecation warnings and for 1.9 compatiblity
+ * Converts templates to more modern foo.html.erb naming
+
+Last commit to the main repository was on March 30th, 2009. 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. **Also:** If anyone else creates generally useful enhancements to this utility please start by forking this and then issue me a pull request.
+
+**Note:** This plugin should work for Rails 2.X and Rails 3. Support for Rails 3 has been confirmed in the latest revision (with fixed deprecation warnings).
+
+## Installation ##
+
+All you have to do is install it into your Rails 2 or 3 project.
+
+ gem install query_reviewer
+
+Right now if you use bundler, simply add this to your Gemfile:
+
+ # Gemfile
+ gem "query_reviewer", :git => "git://github.com/nesquena/query_reviewer.git"
+
+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:
+
+ script/plugin install git://github.com/nesquena/query_reviewer.git
+
+In Rails 2, the rake tasks are not loaded automatically (as a gem), you’ll need to add the following to your Rakefile:
+
+ # Rakefile
+ begin
+ require 'query_reviewer/tasks'
+ rescue LoadError
+ STDERR.puts "The query_reviewer gem could not be found!"
+ end
+
+You can then run:
+
+ $ rake query_reviewer:setup
+
+Which will create `config/query_reviewer.yml` in your application, see below for what these options mean.
+If you don't create a config file, the gem will use the default in `vendor/plugins/query_reviewer`.
+
+## Configuration ##
+
+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!)
+
+ * `enabled`: whether any output or query analysis is performed. Set this false in production!
+ * `inject_view`: controls whether the output automatically is injected before the &lt;/body&gt; in HTML output.
+ * `profiling`: when enabled, runs the MySQL SET PROFILING=1 for queries longer than the `warn_duration_threshold` / 2.0
+ * `production_data`: whether the duration of a query should be taken into account
+ * `stack_trace_lines`: number of lines of call stack to include in the "short" version of the stack trace
+ * `trace_includes_vendor`: whether the "short" verison of the stack trace should include files in /vendor
+ * `trace_includes_lib`: whether the "short" verison of the stack trace should include files in /lib
+ * `warn_severity`: the severity of problem that merits "WARNING" status
+ * `critical_severity`: the severity of problem that merits "CRITICAL" status
+ * `warn_query_count`: the number of queries in a single request that merits "WARNING" status
+ * `critical_query_count`: the number of queries in a single request that merits "CRITICAL" status
+ * `warn_duration_threshold`: how long a query must take in seconds (float) before it's considered "WARNING"
+ * `critical_duration_threshold`: how long a query must take in seconds (float) before it's considered "CRITICIAL"
+
+## Example ##
+
+If you disable the inject_view option above, you'll need to manually put the analyzer's output into your view:
+
+ # view.html.haml
+ = query_review_output
+
+and that will display the analyzer view!
+
+## Resources ##
+
+Random collection of resources that might be interesting related to this utility:
+
+ * <http://blog.purifyapp.com/2010/06/15/optimise-your-mysql/>
+ * <http://www.tatvartha.com/2009/09/rails-optimizing-database-indexes-using-query_analyzer-and-query_reviewer/>
+ * <http://www.geekskillz.com/articles/using-indexes-to-improve-rails-performance>
+ * <http://www.williambharding.com/blog/rails/rails-mysql-indexes-step-1-in-pitiful-to-prime-performance/>
+ * <http://guides.rubyonrails.org/performance_testing.html>
+
+Other related gems that prove useful for database optimization:
+
+ * [bullet](https://github.com/flyerhzm/bullet)
+ * [slim-scrooge](https://github.com/sdsykes/slim_scrooge)
+ * [slim-attributes](https://github.com/sdsykes/slim-attributes)
+
+## Alternatives ##
+
+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:
+
+ * [rack-bug](https://github.com/brynary/rack-bug)
+ * [rails-footnotes](https://github.com/josevalim/rails-footnotes)
+ * [newrelic-development](http://support.newrelic.com/kb/docs/developer-mode)
+ * [palmist](https://github.com/flyingmachine/palmist)
+ * [query_diet](https://github.com/makandra/query_diet)
+ * [query_trace](https://github.com/ntalbott/query_trace)
+
+Know of a better alternative? Let me know!
+
+## Acknowledgements ##
+
+Created by Kongregate & David Stevenson.
+Refactorings and compilations of all fixes since was done by Nathan Esquenazi.
+Also, ajvargo for helping with some fixes.
+
+Copyright (c) 2007-2008 Kongregate & David Stevenson, released under the MIT license
View
@@ -1,6 +1,8 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
+require 'bundler'
+Bundler::GemHelper.install_tasks
desc 'Default: run unit tests.'
task :default => :test
View
14 init.rb
@@ -1,13 +1 @@
-# Include hook code here
-
-require 'query_reviewer'
-
-if QueryReviewer.enabled?
- ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:include, QueryReviewer::MysqlAdapterExtensions)
- ActionController::Base.send(:include, QueryReviewer::ControllerExtensions)
- Array.send(:include, QueryReviewer::ArrayExtensions)
-
- if ActionController::Base.respond_to?(:append_view_path)
- ActionController::Base.append_view_path(File.dirname(__FILE__) + "/lib/query_reviewer/views")
- end
-end
+require File.dirname(__FILE__) + "/rails/init"
View
@@ -5,47 +5,46 @@
module QueryReviewer
CONFIGURATION = {}
-
+
def self.load_configuration
default_config = YAML::load(ERB.new(IO.read(File.join(File.dirname(__FILE__), "..", "query_reviewer_defaults.yml"))).result)
-
+
CONFIGURATION.merge!(default_config["all"] || {})
- CONFIGURATION.merge!(default_config[RAILS_ENV || "test"] || {})
-
- app_config_file = File.join(RAILS_ROOT, "config", "query_reviewer.yml")
-
- if File.exist?(app_config_file)
+ CONFIGURATION.merge!(default_config[Rails.env || "test"] || {})
+
+ app_config_file = Rails.root + "config/query_reviewer.yml"
+
+ if app_config_file.exist?
app_config = YAML.load(ERB.new(IO.read(app_config_file)).result)
- CONFIGURATION.merge!(app_config["all"] || {})
- CONFIGURATION.merge!(app_config[RAILS_ENV || "test"] || {})
+ CONFIGURATION.merge!(app_config["all"] || {})
+ CONFIGURATION.merge!(app_config[Rails.env || "test"] || {})
end
-
+
if enabled?
- begin
+ begin
CONFIGURATION["uv"] ||= !Gem.searcher.find("uv").nil?
if CONFIGURATION["uv"]
require "uv"
end
rescue
- CONFIGURATION["uv"] ||= false
+ CONFIGURATION["uv"] ||= false
end
- end
+
+ require "query_reviewer/query_warning"
+ require "query_reviewer/array_extensions"
+ require "query_reviewer/sql_query"
+ require "query_reviewer/mysql_analyzer"
+ require "query_reviewer/sql_sub_query"
+ require "query_reviewer/mysql_adapter_extensions"
+ require "query_reviewer/controller_extensions"
+ require "query_reviewer/sql_query_collection"
+ end
end
-
+
def self.enabled?
CONFIGURATION["enabled"]
end
end
-QueryReviewer.load_configuration
-
-if QueryReviewer.enabled?
- require "query_reviewer/query_warning"
- require "query_reviewer/array_extensions"
- require "query_reviewer/sql_query"
- require "query_reviewer/mysql_analyzer"
- require "query_reviewer/sql_sub_query"
- require "query_reviewer/mysql_adapter_extensions"
- require "query_reviewer/controller_extensions"
- require "query_reviewer/sql_query_collection"
-end
+# Rails Integration
+require 'query_reviewer/rails' if defined?(Rails)
@@ -1,3 +1,4 @@
+require "action_view"
require File.join(File.dirname(__FILE__), "views", "query_review_box_helper")
module QueryReviewer
@@ -7,7 +8,10 @@ class QueryViewBase < ActionView::Base
end
def self.included(base)
- base.alias_method_chain :perform_action, :query_review if QueryReviewer::CONFIGURATION["inject_view"]
+ if QueryReviewer::CONFIGURATION["inject_view"]
+ alias_name = defined?(Rails::Railtie) ? :process_action : :perform_action
+ base.alias_method_chain(alias_name, :query_review)
+ end
base.alias_method_chain :process, :query_review
base.helper_method :query_review_output
end
@@ -38,23 +42,24 @@ def add_query_output_to_view(total_time)
if response.body.is_a?(String) && response.body.match(/<\/body>/i) && Thread.current["queries"]
idx = (response.body =~ /<\/body>/i)
html = query_review_output(false, total_time)
- response.body.insert(idx, html)
+ response.body = response.body.insert(idx, html)
end
end
end
- def perform_action_with_query_review
+ def perform_action_with_query_review(*args)
Thread.current["query_reviewer_enabled"] = cookies["query_review_enabled"]
t1 = Time.now
- r = perform_action_without_query_review
+ r = defined?(Rails::Railtie) ? process_action_without_query_review(*args) : perform_action_without_query_review(*args)
t2 = Time.now
add_query_output_to_view(t2 - t1)
r
end
+ alias_method :process_action_with_query_review, :perform_action_with_query_review
- def process_with_query_review(request, response, method = :perform_action, *arguments) #:nodoc:
+ def process_with_query_review(*args) #:nodoc:
Thread.current["queries"] = SqlQueryCollection.new
- process_without_query_review(request, response, method, *arguments)
+ process_without_query_review(*args)
end
end
-end
+end
@@ -18,15 +18,15 @@ def analyze_select_type!
def analyze_query_type!
case query_type
- when "system", "const", "eq_ref":
+ when "system", "const", "eq_ref" then
praise("Yay")
- when "ref", "ref_or_null", "range", "index_merge":
+ when "ref", "ref_or_null", "range", "index_merge" then
praise("Not bad eh...")
- when "unique_subquery", "index_subquery":
+ when "unique_subquery", "index_subquery" then
#NOT SURE
- when "index":
+ when "index" then
warn(:severity => 8, :field => "query_type", :desc => "Full index tree scan (slightly faster than a full table scan)") unless !extra.include?("using where")
- when "all":
+ when "all" then
warn(:severity => 9, :field => "query_type", :desc => "Full table scan") unless !extra.include?("using where")
end
end
@@ -0,0 +1,37 @@
+require 'query_reviewer'
+
+module QueryReviewer
+ def self.inject_reviewer
+ # Load adapters
+ ActiveRecord::Base
+ adapter_class = ActiveRecord::ConnectionAdapters::MysqlAdapter if defined? ActiveRecord::ConnectionAdapters::MysqlAdapter
+ adapter_class = ActiveRecord::ConnectionAdapters::Mysql2Adapter if defined? ActiveRecord::ConnectionAdapters::Mysql2Adapter
+ adapter_class.send(:include, QueryReviewer::MysqlAdapterExtensions) if adapter_class
+ # Load into controllers
+ ActionController::Base.send(:include, QueryReviewer::ControllerExtensions)
+ Array.send(:include, QueryReviewer::ArrayExtensions)
+ if ActionController::Base.respond_to?(:append_view_path)
+ ActionController::Base.append_view_path(File.dirname(__FILE__) + "/lib/query_reviewer/views")
+ end
+ end
+end
+
+if defined?(Rails::Railtie)
+ module QueryReviewer
+ class Railtie < Rails::Railtie
+ rake_tasks do
+ load File.dirname(__FILE__) + "/tasks.rb"
+ end
+
+ initializer "query_reviewer.initialize" do
+ QueryReviewer.load_configuration
+
+ QueryReviewer.inject_reviewer if QueryReviewer.enabled?
+ end
+ end
+ end
+else # Rails 2
+ QueryReviewer.load_configuration
+
+ QueryReviewer.inject_reviewer
+end
Oops, something went wrong.

0 comments on commit 8202e49

Please sign in to comment.