Search code examples
ruby-on-railsajaxperformancespreeselect2-rails

Slow query performance fetching keyword taxons in Spree extension


I'm working on adding functionality to an existing Spree custom photo printing store to allow photographers to upload their portfolios and sell photos through the site. I created a select2 text field for adding keywords to products using Spree::Taxon(s), and it works fine. I have fields for adding keywords in each language that the site supports (English and French).

However, the ajax query takes an extremely long time to complete (5-15s on average). The ActiveRecord query takes between 5-150ms to complete, and the view rendering takes no more than 60ms to complete. I can't account for the rest of the load time. Does anyone have advice on speeding up returning the result or what could be behind the extra time it takes to complete?

Using MySQL for the database, Ruby 2.2.1 and Rails 4.2.1. My dev environment is: Mac Mini (8gb ram, HDD), Aptana Studio IDE, server running on localhost:3000.

Please don't hesitate to request more clarifying information! I wasn't sure exactly what I needed to post to help with the context of my issue.

Controller to return JSON for the ajax request:

class KeywordTagsController < Spree::StoreController
  respond_to :json
  def find_keywords
    term = params[:q]
    Rails.logger.debug params.inspect
    if params[:locale_str]
      query = []
      query = ["spree_taxons.name like ?", term + '%'] if term

      locale = params[:locale_str].to_sym
      keyword_taxonomy = Spree::Taxonomy.find_by(name: Spree.t("pi-taxonomy-keyword"))
      keyword_taxons = keyword_taxonomy.taxons.with_translations(locale).where(query).order('name asc').select{ |t| t.parent_id != nil} if locale
      respond_with keyword_taxons if keyword_taxons
    end
  end

end

Select2 initializer Javascript:

$("#keywords_en").select2({
          createSearchChoice: function(term, data) {
             if ($(data).filter(function() {
                return this.text.localeCompare(term) === 0;
                }).length === 0) {
                    return {
                        id: term,
                        text: term
                    };
                }
          },
          multiple: true,
          ajax: {
              url: '/keywords/en',
              dataType: 'json',
              data: function (params) {
                        return {
                            q: params // search term
                        };
              },
              results: function(data){
                  return { results: $.map( data, function (keyword, i) {
                      return {id: keyword.id, text: keyword.name }
                  })}
              }
          },
          tags: true,
          tokenSeparators: [','],
          placeholder: '<%= Spree.t('pi-keywords-placeholder-en') %>',
          initSelection: function (element, callback) {
            var data = [];

            function splitVal(string, separator) {
                var val, i, l;
                if (string === null || string.length < 1) return [];
                val = string.split(separator);
                for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
                return val;
            }

            $(splitVal(element.val(), ",")).each(function () {
                data.push({
                    id: this,
                    text: this
                });
            });

            callback(data);
         }
        });

Some console output for the request (some of the faster examples):

15:00:51 INFO: Processing by KeywordTagsController#find_keywords as JSON 
15:00:51 INFO:   Parameters: {"q"=>"", "_"=>"1436986845195", "locale_str"=>"fr"} 
15:00:54 INFO: Completed 200 OK in 2870ms (Views: 40.6ms | ActiveRecord: 5.2ms) 
15:33:45 INFO: Started GET "/keywords/fr?q=mer&_=1436986845196" for 127.0.0.1 at 2015-07-15 15:33:45 -0400 
15:33:48 INFO: Processing by KeywordTagsController#find_keywords as JSON 
15:33:48 INFO:   Parameters: {"q"=>"mer", "_"=>"1436986845196", "locale_str"=>"fr"} 
15:33:50 INFO: Completed 200 OK in 2136ms (Views: 5.4ms | ActiveRecord: 113.4ms) 
15:33:58 INFO: Started GET "/keywords/fr?q=&_=1436986845197" for 127.0.0.1 at 2015-07-15 15:33:58 -0400 
15:33:58 INFO: Processing by KeywordTagsController#find_keywords as JSON 
15:33:58 INFO:   Parameters: {"q"=>"", "_"=>"1436986845197", "locale_str"=>"fr"} 
15:34:00 INFO: Completed 200 OK in 1885ms (Views: 38.7ms | ActiveRecord: 4.6ms) 

Solution

  • It turns out that fetching the query results was only slow because I was in the dev environment. In production, it works at the speed one would expect. I'm posting this answer in case others have the same question!