ruby-on-rails – 如何优化数据库查询

我有两种情况需要很长时间才能加载页面,而且我不知道如何在最近开始使用RoR时更快地调用数据库.

案例A.

我试图显示根类别(使用祖先宝石)和与这些根类别相关联的供应商数量.共有15个根类别.

结果如下:

>时尚(14)
>汽车(26)
> ……

suppliers.html.erb

<% Category.roots.each do |category| %>
    <li class="pointer txt-hover-grey mili-margin-bottom">
        <span class="micro-margin-right">
            <%= link_to category.name,category_suppliers_path(category),:title => category.name %>
        </span>
        <span class="txt-alt">
            (<%= category.suppliers_count_active %>)
        </span>
    </li>
<% end %>

category.rb

def suppliers_count_active
    self.suppliers.where(:active => true).pluck(:id).count
end

案例B(祖先宝石)

这与主要类别菜单有关(就像您可以在任何电子商店中找到的那样).有15个根类别(级别0),然后每个根类别有3个子类别(总共45个),每个子类别有大约5个子子类别(总共大约225个).对于每个子子类别,我也填充该类别中的产品数量.

结果如下:

>时尚

>男士们

> T恤(34555)
>内衣(14555)
> ……

>女人

> T恤(43000)
>内衣(23000)

>运动

>单板滑雪

> XYT(2323)
> ……

> ……

> ……

categories_menu.html.erb

<div class="content no-padding padding-static relative table menu-nr">
 <!--   root_categories -->
<% Category.includes(:image,:products).serializable.each do |root| %>
    <div class="table-center container-center full-h categories-trigger">
        <%= link_to Category.find(root['id']).category_link,:title => root['name'] do %>                
            <div class="uppercase full-h size-tiny semi-bold txt-hover-main_light semi-padding-top semi-padding-bottom">
            <%= root['name'] %>
            </div>
        <% end %>
        <div class="categories-hide categories-dropdown shadow z-1000 bg-white txt-black size-tiny">
            <div class="table full-w inwrap-dropdown">
                <div class="cell">
                    <div class="table dropdown-left">
                    <% 
                        children_sorted = root['children'].sort_by { |child| child['products_sum_count'] }.reverse!.first(3)
                        children_sorted.each do |cat| %>
                        <div class="cell container-left">
                            <div class="table">
                                <div class="cell container-top">
                                    <div class="mili-margin-left mili-margin-right">
                                    <% cat2 = Category.find_by(:id => cat['id'])
                                    if !cat2.image.blank? %>
                                        <%= image_tag(cat2.image.image.url(:small),:title => cat2.image.title,:alt => cat2.image.title,:class => "img-category") %> 
                                        <% end %>    
                                    </div>
                                </div>
                                <div class="cell">
                                    <h5 class="mili-margin-bottom">
                                        <%= link_to "#{cat['name']}",Category.find(cat['id']).category_link,:title => cat['name'] %>
                                    </h5>
                                    <div class="txt-grey_dark semi_bold mili-margin-bottom">
                                    <% 
                                       # cat_children = cat.children.includes(:products)
                                        cat['children'].first(7).each do |sub_cat| 
                                    %>  
                                        <%= link_to Category.find(sub_cat['id']).category_link,:title => sub_cat['name'],:class => "block txt-hover-grey micro-margin-bottom" do %>
                                            <%= "#{sub_cat['name']}" %> <span class="txt-alt"><%= "(#{sub_cat['products_sum_count']})" %></span>
                                        <% end %>
                                    <% end %>
                                    </div>

                                    <%= link_to "Další kategorie >",:class => "semi-margin-top block txt-alt txt-hover-alt_dark" %>
                                </div>
                            </div>
                        </div>
                    <% end %>
                    </div>
                </div>
                <div class="cell bg-grey_light semi-padding-left">
                    <div class="table">
                        <div class="cell container-left">
                            <div class="mili-margin-left mili-margin-right">
                                <h5 class="txt-alt mili-margin-bottom">
                                    <%= t(:menu_suppliers_title) %>
                                </h5>

                                <% 
                                suppliers = supplier.joins(:categories).where(:active => true,categories: { :id => root['id'] }).last(3)
                                suppliers.each do |supplier| 
                                %>
                                <% cache supplier do %>
                                <div class="table relative mili-margin-bottom">
                                    <div class="cell inline relative wrap-shop">
                                        <div class="absolute-center-nr center inwrap-shop inwrap-shop-rohlik btn border">
                                            <%= link_to supplier_path(supplier),:title => "#{t(:menu_suppliers_link_title)} #{supplier.name}" do %>
                                                <%= image_tag(supplier.image.image.url(:small),:alt => supplier.image.title) if !supplier.image.blank? %>
                                            <% end %>
                                        </div>
                                    </div>
                                    <div class="col inline semi-margin-left-nr">
                                        <div class="table txt-avatar-small full-w">
                                            <div class="table-center">
                                                <%= link_to supplier.name,supplier_path(supplier),:title => "#{t(:menu_suppliers_link_title)} #{supplier.name}",:class => "semi-bold block micro-margin-bottom" %>
                                                <div class="txt-alt">
                                                    <%= t(:homepage_suppliers_logo_text,:commission => supplier.commission_donated,:commission_type => supplier.commission_type ) %>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <% end %>
                                <% end %>
                                <span class="block txt-alt txt-hover-alt_dark half-margin-bottom">
                                </span>
                                <%#= link_to t(:menu_suppliers_link_others),category_suppliers_path(:id => root['id']),:title => t(:menu_suppliers_link_others),:class => "block txt-alt txt-hover-alt_dark half-margin-bottom" %>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="categories-hide wrap-categories-arrow relative">
            <div class="categories-arrow absolute z-1000">
            </div>
        </div>
    </div>
<% end %>
</div>

category.rb

def self.serializable
  Category.includes(:translations).where(categories: {:active => true,:ancestry_depth => 0..2 },category_translations: {:locale => I18n.locale.to_s} ).arrange_serializable(:order => 'category_translations.name') 
end

def category_link
   category_path(self)
end

这两种情况都需要几秒钟才能加载.任何建议真的很感激.

谢谢,
米罗斯拉夫

更新1:

在这里,您可以看到NewRelic的输出.在尝试实现dalli memcache和identity_cache之后,它与案例B有关.我还上传菜单的屏幕截图.

> NewRelic Output
> Menu

更新2:

最耗时的部分似乎是以下代码

result = Benchmark.ms { Category.includes(:translations).where(categories: {:active => true,category_translations: {:locale => I18n.locale.to_s} ).arrange_serializable(:order => 'category_translations.name') }
=> 7207.116272300482

生成层次结构中所有活动类别(大约1000)的哈希值,因此我可以为菜单正确呈现它.

不确定如何优化这部分.

更新3

我使用postgres数据库.

CategoryTranslation表

create_table "category_translations",force: :cascade do |t|
  t.integer  "category_id",null: false
  t.string   "locale",null: false
  t.datetime "created_at",null: false
  t.datetime "updated_at",null: false
  t.string   "name"
end

add_index "category_translations",["category_id"],name: "index_category_translations_on_category_id",using: :btree
add_index "category_translations",["locale"],name: "index_category_translations_on_locale",using: :btree

分类

create_table "categories",force: :cascade do |t|
  t.string   "name"
  t.boolean  "active",default: false
  t.integer  "level"
  t.datetime "created_at",null: false
  t.string   "ancestry"
  t.string   "mapping"
  t.integer  "products_count",default: 0,null: false
  t.integer  "products_sum_count",default: 0
  t.integer  "ancestry_depth",default: 0
  t.string   "category_link"
  t.string   "image_link"
end

add_index "categories",["ancestry"],name: "index_categories_on_ancestry",using: :btree

解决方法

案例A.

这里最好的做法是在类别模型中缓存活动供应商的计数.

>在Category模型中添加active_supliers_count列
>将after_save挂钩添加到供应商模型,并在其变为活动/非活动时递增/递减类别的计数器

案例B

这里的问题与案例A中的问题相同,您需要添加缓存计数器.

看来你在循环中创建了多个包含.您可以只使用所需的一切.

例如

Category.includes(children: [:image,:products])

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...