Этот журнал рельсов - очень полезная вещь, но ее часто забывают. Сначала он может выглядеть как gibberi sh, поэтому давайте рассмотрим его, чтобы увидеть замедление; после Processing by ArticlesController#index as HTML
, где он начинает отображать вашу индексную страницу.
Первое, что он делает:
Article Load (149.4ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" DESC LIMIT $1 [["LIMIT", 1]]
↳ app/views/articles/index.html.erb:2
Показывает вызываемый запрос к БД (получить последнюю статью), сколько времени это займет (149 мс) и что это требуется из-за вашего кода в строке 2 index. html .erb. И в строке 2 у вас есть @articles.last.image
- это вызывает тот запрос к БД.
149 мс, ничего страшного ... оставайтесь здесь, это путешествие.
Следующее. это еще 2 запроса к БД, также вызванные строкой 2
ActiveStorage::Attachment Load (102.9ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_type" = $1 AND "active_storage_attachments"."name" = $2 AND "active_storage_attachments"."record_id" = $3 [["record_type", "Article"], ["name", "image"], ["record_id", 8]]
↳ app/views/articles/index.html.erb:2
ActiveStorage::Blob Load (33.3ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 [["id", 7]]
↳ app/views/articles/index.html.erb:2
На этот раз он получает ресурс изображения, и это занимает еще 102 мс + 33 мс. Но ваш контроллер использует Model.with_attached_image
для предварительной загрузки изображения, не так ли? Что ж, очевидно, что это не работает. Взгляните на https://jasoncharnes.com/eager-loading-querying-against-activestorage-attachments/, чтобы получить хорошее руководство по предварительной загрузке.
Я думаю, что .all
у вас не в том месте. Вы должны использовать Model.with_attached_image.all
вместо Model.all.with_attached_image
.
Но есть еще кое-что ...
Затем есть 3 запроса к базе данных, требуемые строкой 4 в представлении:
CACHE Article Load (0.0ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" DESC LIMIT $1 [["LIMIT", 1]]
↳ app/views/articles/index.html.erb:4
CACHE ActiveStorage::Attachment Load (0.0ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_type" = $1 AND "active_storage_attachments"."name" = $2 AND "active_storage_attachments"."record_id" = $3 [["record_type", "Article"], ["name", "image"], ["record_id", 8]]
↳ app/views/articles/index.html.erb:4
CACHE ActiveStorage::Blob Load (0.0ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 [["id", 7]]
↳ app/views/articles/index.html.erb:4
Но обратите внимание, что все это занимает 0,0 мс и кэшируется. Это потому, что предыдущие запросы, вызванные строкой 2, уже получили эти данные из БД. Отлично!
Следите за такими деталями в журналах во время разработки. Обратите внимание, когда строка начинается с CACHE, это хорошо.
Затем у вас есть 15 некэшированных запросов к базе данных, вызванных строками 8, 11, 14, 17 и 20, где вы используете области категорий для получения данных, без каких-либо предварительная загрузка данных изображения (@articles.business.last.image
). Итак, каждый вызов области действия выполняет 3 запроса к БД.
Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."category" = $1 ORDER BY "articles"."id" DESC LIMIT $2 [["category", "sports"], ["LIMIT", 1]]
↳ app/views/articles/index.html.erb:8
ActiveStorage::Attachment Load (0.5ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_type" = $1 AND "active_storage_attachments"."name" = $2 AND "active_storage_attachments"."record_id" = $3 [["record_type", "Article"], ["name", "image"], ["record_id", 6]]
↳ app/views/articles/index.html.erb:8
ActiveStorage::Blob Load (0.3ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 [["id", 5]]
↳ app/views/articles/index.html.erb:8
Надеюсь, это показало вам, как определить, куда идет время в ваших журналах.
Чтобы начать исправлять это, начните с малого. Сделайте один вызов, чтобы получить данные последней статьи и изображение
контроллер
@latest_article = Articles.with_attached_image.last
просмотр
<div class="main" style="background-image: url(<%= (url_for(@latest_article.image)) %>)">
<div class="top-article" >
<h2><%= @latest_article.title %></h2>
<p><%= link_to "Read more..." %></p>
</div>
</div>
Это должно привести к 3 запросам БД для строк 2 и 4 вниз на 1 запрос. Проверьте журнал и посмотрите, как он изменился.
Далее следуют запросы с заданной областью.
Вы можете создавать явные вызовы для каждой категории в контроллере, предварительно выбирая данные изображения в каждой:
@tech_article = Article.with_attached_image.where(category: 'tech').last
@news_article = Article.with_attached_image.where(category: 'news').last
# and so on...
Таким образом у вас будет один вызов БД для каждой категории - намного меньше, чем 15
Но я замечу, что для них вы показываете только изображение, а не заголовок. Это просто для краткости сообщения здесь?
В идеале, вы хотите свести все это к одному запросу к БД; но для этого потребуется вложенный запрос SQL; что может даже вызвать собственный вопрос.
Замечания по производственному развертыванию
В производственной среде все вызовы GET к изображениям будут загружаться намного быстрее, чем в вашей среде разработки. Возможно, разместите его онлайн на скрытой странице, чтобы вы могли видеть, как он работает в производстве - как только вы уменьшите количество запросов к БД до 1 или 2
В разработке вы обслуживаете все из одного потока сервера; так что все происходит одно за другим. При производстве запросы изображений (все запросы GET в вашем журнале, кроме первого запроса GET для индекса) будут выполняться одновременно. Это окажет огромное влияние на время загрузки 15 секунд, которое вы видите.