How to optimize database queries

I have two cases where it takes a lot of time to load pages, and I'm not sure how to make database calls faster when I started with RoR recently.

Case A

I am trying to show the categories of roots (using the pedigree pearl) and the number of providers that are associated with any of these root categories. Only 15 categories of roots.

The result looks something like this:

  • Fashion (14)
  • Auto (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

Case B (Ancestral Gem)

(, eshop). 15 ( 0), 3 ( 45), 5 ( 225). subsub .

:

    • Mens
      • (34555)
      • (14555)
      • ...
      • (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 >", Category.find(cat['id']).category_link, :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

. .

, Miroslav

1:

NewRelic. B, dalli memcache identity_cache. , .

2:

:

result = Benchmark.ms { Category.includes(:translations).where(categories: {:active => true, :ancestry_depth => 0..2 }, 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.datetime "updated_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
+4
5

A

, Category.

  • active_supliers_count Category model
  • after_save / /

B

, A, .

, . , .

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

, pluck on

self.suppliers.where(:active => true).pluck(:id).count?

, self.suppliers.where(:active => true).count, pluck id, , .

0

. . ? ? category_id ( ). ? ? 255 varchar , mysql2 varchar 190. , , , , . . .

0

A

. , , ruby ​​ group_by?

active_suppliers = Suppliers.where(:active => true).select('id, category_id')
@category_suppliers = active_suppliers.group_by(&:category_id)
# =>  {2 =>[#<Supplier id: 4, category_id: 2>, ...], 3 => ...}

( ). , , -, , :

<span class="txt-alt">
  (<%= @category_suppliers[category.id].length %>)
</span>

B

, , , , ? , - . arrange_serializable , , . node , .

:

<% children_sorted = root['children'].sort_by { |child| child['products_sum_count'] }.reverse!.first(3)

:

<% children_sorted = root.children.sort_by { |child| child['products_sum_count'] }.reverse!.first(3)

, . :

<%= link_to Category.find(sub_cat['id']).category_link, ...%>

id, ?

<%= link_to category_path(sub_cat['id']), ...%>

, , "/: id"? ? , , , , ?

: , , . -, , , , (...root['children'].sort_by { |child| child['products_sum_count'] }.reverse!.first(3)) , model/class , unit test, , ? , .

0

A

, .

B

, . , .

0
source

Source: https://habr.com/ru/post/1612309/


All Articles