简体   繁体   中英

Rails Database Query ROR

First of all, I am still new to ROR and I am trying to come up with more efficient way to do a database query for my datatables.

My Model association

class Store < ActiveRecord::Base
  has_many :surveys
  has_many :customers 
end
...
class Survey < ActiveRecord::Base
  belongs_to :store
end
...
class Customer < ActiveRecord::Base
  belongs_to :store
end

In my DataTables

          <tbody>
            <% @store.surveys.each do |survey| %>
            <tr class="th-container table-fixer">
              <td><%= find_customer_id(survey.email).nil? ? survey.first_name : link_to(survey.first_name, store_customer_path(@store, find_customer_id(survey.email))) %></td>
              <td><%= get_ltv(survey) %></td>         
            </tr>
            <% end %>
          </tbody>

find_customer_id and get_ltv method as follows

def find_customer_id(customer_email)
   BwCustomer.find_by(email: customer_email)
end

The problem with the code is that, currently I have over 1000 active record objects that I loop through, when find_customer_id method is hit it will find customer with the given email address and the query takes over 15 sec to process.

In my situation, what would be the best way to approach this?

solution that I have though about: 1. join the tables to so that I don't have to call another table 2. lazy load, only load the objects when needed

Some suggestion will be greatly appreciated

thank you

Your query by email ID should not take so much time.

  1. Add index for the email column in Customers table (Refer this for adding indexes through Active record migrations - http://apidock.com/rails/v4.2.1/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index )

  2. Your code shows calling the find_customer_id twice. Do that once so only 1 database query is fired

  3. You need not write a wrapper method - Customer.find_by_email(customer_email) also works

To optimize further, you can collect all the customer IDs you need to check for existence in database in one loop, and fire a single database query: Customer.where(email: [list of customer emails])

The main problem is that you're missing an association between customer and survey. You could make one by joining on the email

class Survey < ActiveRecord::Base
  belongs_to :customer, primary_key: :email, foreign_key: :email
end

but this is a somewhat sketchy approach. Does you application know the ID of the customer when they fill a survey? Or can these surveys be filled by anyone and you make the link if someone claims to have the same email as a customer?

In any case you need both the email columns to be indexed and if you make an association between the two you will be able to write the following in your controller code.

@store = Store.includes(surveys: :customer).find(params[store_id])

This will make a database query which eager loads all the surveys and customers that you're about to display so that inside the loop you can use survey.customer without calling a new query for each row.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM