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
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我們的時間!
謝謝!這很好。服務器日誌不再顯示每個項目查詢,並執行Order Order而不是Order Exists。平均加載時間已經下降了大約25毫秒。 –
@bloodrunner太棒了!作爲SO說謝謝的方式,如果你對答案感到滿意,你能接受嗎? –
博格肯定的事情!謝謝我還是新來的SO) –