0

我注意到,隨着我一直在開發我的應用程序並創建大量項目/列出加載時間越來越長。我懷疑這是我在控制器中查詢數據庫的方式。該視圖使用erb來執行@ item.each並檢查@ item.orders.any?並只顯示沒有訂單的項目。該代碼基本上必須經過數據庫中的每一個項目執行此檢查,然後呈現結果,我懷疑這將是一個超過100多項的噩夢。Rails - 加速我的項目#索引動作與數據庫查詢

有沒有更聰明的方法來做到這一點?

這是簡單的市場應用程序,買賣雙方可以進行業務。賣家列出了一個項目,並將其顯示在Items#Index頁面上以及其他項目。買家點擊它並點擊購買,然後將它們帶到訂單頁面,然後他們可以使用PayPal進行結賬。收到PayPal IPN後,訂單將被提交給數據庫。

這裏是代碼:從服務器日誌加載索引行動

Started GET "/" for 73.110.34.200 at 2017-07-31 13:19:38 -0500 
Cannot render console from 73.110.34.200! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 
Processing by ItemsController#index as */* 
    Rendering items/index.html.erb within layouts/application 
    Item Load (10.3ms) SELECT "items".* FROM "items" ORDER BY "items"."created_at" DESC, created_at DESC 
    Order Exists (1.7ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 19], ["LIMIT", 1]] 
    Order Exists (3.2ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 18], ["LIMIT", 1]] 
    Order Exists (0.4ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 17], ["LIMIT", 1]] 
    Order Exists (0.7ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 16], ["LIMIT", 1]] 
    Order Exists (0.6ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 15], ["LIMIT", 1]] 
    Order Exists (0.6ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 14], ["LIMIT", 1]] 
    Order Exists (0.8ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 13], ["LIMIT", 1]] 
    Order Exists (0.6ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 12], ["LIMIT", 1]] 
    Order Exists (0.8ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 11], ["LIMIT", 1]] 
    Order Exists (0.4ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 10], ["LIMIT", 1]] 
    Order Exists (0.8ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 9], ["LIMIT", 1]] 
    Order Exists (3.7ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 8], ["LIMIT", 1]] 
    Order Exists (0.5ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 7], ["LIMIT", 1]] 
    Order Exists (0.5ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 6], ["LIMIT", 1]] 
    Order Exists (0.6ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 5], ["LIMIT", 1]] 
    Order Exists (0.4ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 4], ["LIMIT", 1]] 
    Order Exists (0.5ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 3], ["LIMIT", 1]] 
    Order Exists (0.4ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 2], ["LIMIT", 1]] 
    Order Exists (0.8ms) SELECT 1 AS one FROM "orders" WHERE "orders"."item_id" = $1 LIMIT $2 [["item_id", 1], ["LIMIT", 1]] 
    Rendered items/index.html.erb within layouts/application (226.2ms) 
    Rendered layouts/_rails_default.html.erb (194.0ms) 
    Rendered layouts/_shim.html.erb (0.5ms) 
    Rendered layouts/_header.html.erb (20.0ms) 
    Rendered layouts/_messages.html.erb (1.1ms) 
Completed 200 OK in 666ms (Views: 564.1ms | ActiveRecord: 28.3ms) 

上述ItemsController

摘錄
class ItemsController < ApplicationController 
    before_action :set_item, only: [:show, :edit, :update, :destroy] 
    before_action :authenticate_user!, except: [:index, :show] 
    rescue_from ActiveRecord::RecordNotFound, with: :deny_access 
    rescue_from ActionView::MissingTemplate, with: :template_not_found 


    def garage 
    @items = current_user.items 
    end 

    def show 
    @item = Item.find(params[:id]) 
    end 

    # GET /items 
    # GET /items.json 
    def index 
    @items = Item.all 
    if params[:search] 
     @items = Item.search(params[:search]).order("created_at DESC") 
    else 
     @items = Item.all.order("created_at DESC") 
    end 
    end 

    # GET /items/new 
    def new 
    @item = current_user.items.build 
    end 

    # GET /items/1/edit 
    def edit 
    end 

    # POST /items 
    # POST /items.json 
    def create 
    @item = current_user.items.build(item_params) 
    @item.username = current_user.username 

    respond_to do |format| 
     if @item.save 
     format.html { redirect_to @item, notice: 'Item was successfully created.' } 
     format.json { render :show, status: :created, location: @item } 
     else 
     format.html { render :new } 
     format.json { render json: @item.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /items/1 
    # PATCH/PUT /items/1.json 
    def update 
    respond_to do |format| 
     if @item.update(item_params) 
     format.html { redirect_to @item, notice: 'Item was successfully updated.' } 
     format.json { render :show, status: :ok, location: @item } 
     else 
     format.html { render :edit } 
     format.json { render json: @item.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /items/1 
    # DELETE /items/1.json 
    def destroy 
    @item.destroy 
    respond_to do |format| 
     format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    def favorite 
    @item = Item.find(params[:id]) 
    type = params[:type] 
    if type == "favorite" 
     current_user.favorites << @item 
     redirect_to :back 

    elsif type == "unfavorite" 
     current_user.favorites.delete(@item) 
     redirect_to :back 

    else 
     redirect_to :back 
    end 
    end 

    def favorites 
    @items = current_user.favorites 
    end 

    def deny_access 
    redirect_to :back 
    rescue ActionController::RedirectBackError 
    redirect_to root_path 
    end 

    def template_not_found 
    redirect_to :back 
    rescue ActionView::MissingTemplate 
    redirect_to root_path 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_item 
     @item = Item.find(params[:id]) 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def item_params 
     params.require(:item).permit(:title, :content, :filepicker_url, :price, :shipping_price, :paypal_email) 
    end 
end 

項目#索引視圖

<div class="row"> 
    <%= form_tag(items_path, :method => "get") do %> 
    <div class="col-lg-6 col-lg-offset-3"> 
     <div class="input-group"> 
     <%= text_field_tag :search, params[:search], placeholder: "Search items...", class: "form-control" %> 
     <div class="input-group-btn"> 
      <%= submit_tag "Search", :name => nil, class: "btn btn-default btn-block" %> 
     </div> 
     </div> 
    </div> 
    <% end %> 
</div> 
<br> 

<% if @items.blank? %> 
    <h4>There are no items containing the term <%= params[:search] %>.</h4> 
<% end %> 

<h1>Items</h1> 
     <% @items.each do |item| %> 
     <% if item.orders.any? %> 
     <% else %> 
      <div class="col-md-3"> 
       <%= link_to(filepicker_image_tag(item.filepicker_url.split(",").last, w: 200, h: 200, fit: 'crop'), item) %><br> 
       <p class="bold"><%= item.title %><br></p> 
       <p><%= link_to number_to_currency(item.price), item %></p> 
       <p class="small"><%= time_ago_in_words(item.created_at) %> ago</p> 
      </div> 
     <% end %> 
     <% end %> 
<br> 

謝謝爲y我們的時間!

回答

1

嘗試使用includes來加載關聯。

class ItemsController < ApplicationController 

    def index 
    if params[:search] 
     @items = Item.search(params[:search]).includes(:orders).order("created_at DESC") 
    else 
     @items = Item.all.includes(:orders).order("created_at DESC") 
    end 
    end 
end 
+0

謝謝!這很好。服務器日誌不再顯示每個項目查詢,並執行Order Order而不是Order Exists。平均加載時間已經下降了大約25毫秒。 –

+1

@bloodrunner太棒了!作爲SO說謝謝的方式,如果你對答案感到滿意,你能接受嗎? –

+0

博格肯定的事情!謝謝我還是新來的SO) –