Ruby on Rails网站很慢;可能是SQL查询的原因吗?

20 浏览
0 Comments

Ruby on Rails网站很慢;可能是SQL查询的原因吗?

我一直在使用Ruby on Rails开发一个网页应用。我已经“完成”了网站,但是它运行非常慢,有时加载页面需要十秒左右的时间。我将这篇文章分成了三个部分:\n

    \n

  1. 概述
  2. \n

  3. 诊断
  4. \n

  5. 可能的想法
  6. \n

\n概述\n作为一个非常粗略的概述,这个网站显示个人项目,每个项目都有自己的页面。每个项目(我在代码中称之为“帖子”)都存储在一个表中。我不确定将整个帖子存储在数据库中是否是一个坏主意,因为一些帖子在正文中有相当多的文本和图片。在posts表中,每个条目都有以下属性:\n

# == Schema Information
#
# 表名: posts
#
#  id                       :integer          not null, primary key
#  title                    :string
#  body                     :text
#  description              :text
#  slug                     :string
#  created_at               :datetime         not null
#  updated_at               :datetime         not null
#  image_file_name          :string
#  image_content_type       :string
#  image_file_size          :integer
#  image_updated_at         :datetime
#  thumbnail_file_name      :string
#  thumbnail_content_type   :string
#  thumbnail_file_size      :integer
#  thumbnail_updated_at     :datetime
#  published                :boolean          default("f")
#  published_at             :datetime
#

\n诊断\n我正在使用Heroku托管应用程序。我已经升级到Hobby级别的dynos,这样我就可以访问它们提供的一些指标,比如吞吐量、内存使用等等。我不认为Heroku是导致网站缓慢的原因,而是我的代码。为了调试,我添加了一个第三方插件Scout,用于跟踪应用程序中的瓶颈。\nScout提供了一个跟踪功能,可以量化应用程序中哪些代码路径花费了最多的时间。如下图所示(在图片的下半部分),有大量的跟踪花费了十秒以上的时间。这并不好...\n\"Scout中的跟踪功能\"\n当我点击第二行(6/17 2:04 PM)时,它给出了响应时间的详细信息:\n\"“/”跟踪的响应时间详细信息\"\n展开SQL语句可以看到,大部分耗时的查询是对帖子数据库的操作,有时还有对帖子进行排序/订购(见下图)。\n\"耗时的SQL语句\"\n可能的想法\n我在这里有什么明显的错误吗?我很困惑,不确定如何加快速度。根据Scout的说法,我有两个想法:\n

    \n

  • 控制器/控制器调用的SQL查询很慢
  • \n

  • HTML中嵌入的Ruby代码很慢。
  • \n

\n控制器/控制器调用的SQL查询很慢:\n下面的代码显示了我在PostsController中为@posts赋值的代码。当用户访问主页时,将运行home方法,当用户转到帖子页面时,将运行index方法。这些查询是否很慢是因为数据库中有相当多的数据(5个帖子的文本和图片)?\n

class PostsController < ApplicationController
  #before_action :authenticate_user!
  before_action :set_post, only: [:show, :edit, :update, :destroy, :publish, :unpublish]
  def home
    @posts = Post.all.published.order('published_at DESC')
  end
  # GET /posts
  # GET /posts.json
  def index
    if user_signed_in? and current_user.admin
      @posts = Post.all.order("id")
    else
      @posts = Post.all.published
    end
  end

\nHTML中嵌入的Ruby代码很慢:\n我在一些HTML代码中使用Ruby来按日期排序帖子和确定最新的帖子。例如,在网站的侧边栏(在主页左边),有一个显示“最新”的部分,其逻辑如下:\n

最新

<% @post=Post.all.published.order("published_at").last %> <% if @post == nil or @post.published_at == nil %> 即将推出! <% else %> <%= render partial: "layouts/media", locals: {post: @post} %> <% end %>

\n同样,在侧边栏的“存档”部分,我按日期排序帖子,做出以下逻辑:\n

<% if Post.published.length != 0 %> 
    

存档

<% @published_posts = Post.published %> <% archives = Hash.new(0) %> <% @published_posts.each do |post| %> <% if archives[post.date] == 0 %> <% archives[post.date] = 1%> <% else %> <% archives[post.date] += 1 %> <% end %> <% end %> <% archives.each do |key, value| %> <% @published_posts.each do |post| %> <% if post.date == key %> <%= link_to post.title, post_path(@post) %> <% end %> <% end %> <% end %> <% end %>

\n我的想法是,也许遍历帖子需要很长时间,但我不完全确定。我觉得这是可以使用的有效代码,但也许其中某些地方非常慢。你们有什么想法吗?还值得注意的是,应用程序的内存使用量非常高:大约500MB。也许这些查询之所以慢是因为获取了大量的数据,但是我不确定对于这样的网页应用程序来说,“大量”数据是什么。当然,我关于网站缓慢的假设可能完全错误,所以我非常愿意听取你们的想法。最后,如果我使用的SQL查询/代码很慢,有没有办法可以加快速度/提高性能?提前感谢你们的帮助!

0
0 Comments

Ruby on Rails 网站运行缓慢的问题可能是由于SQL查询引起的。在这篇文章中,我将整理出这个问题的出现原因以及解决方法。

首先,在文章中提到,在PostsControllerhome方法中,原先使用了Post.all.published.order('published_at DESC')这个查询语句来获取所有已发布的文章。然而,这个查询语句加载了所有的文章和它们的属性到内存中,导致了响应时间非常慢。为了解决这个问题,作者使用了Post.select("attribute")来只选择需要加载的属性,从而显著提高了查询的响应时间。

作者还在其他部分的代码中使用了类似的优化方法。在PostsControllerindex方法中,作者根据用户的权限选择了不同的查询语句,只加载了必要的属性。在嵌入在HTML中的Ruby代码中,作者使用了Post.select来选择需要加载的属性,从而避免了加载不必要的数据。

总结起来,通过选择需要加载的属性,避免加载不必要的数据,可以显著提高Ruby on Rails网站的响应时间。

然而,作者也指出了这种方法的局限性,即需要手动指定除了需要避免的属性以外的所有属性,这很难维护,并且对于其他关于Post的查询,如Post.find,这种方法也不适用。因此,作者提出了一个更好的解决方案,即将body字段拆分成一个独立的PostBody模型和表,并与Post建立belongs_to的关联。这样就可以实现懒加载,然后使用delegate :body, to: :post_body来实现透明访问。

最后,还有他在工作中遇到的类似问题,这个问题几乎发生在20年前。

0
0 Comments

Ruby on Rails网站运行缓慢,可能是由于SQL查询导致的。这个问题的原因是缺乏SQL索引和对Post.all的过多调用。

首先,慢查询涉及到WHERE published = ?。如果posts.published没有建立索引,查询将需要扫描整个表而不仅仅是已发布的帖子。另外,如果没有索引,按posts.published_at排序也会很慢。

为了解决这个问题,在迁移中为posts.publishedposts.published_at添加索引。

add_index(:posts, :published)
add_index(:posts, :published_at)

其次,如果使用Post.allPost.published,意味着将数据库中的所有帖子加载到内存中。如果不是全部使用,这样做就是一种巨大的时间浪费。

例如,在首页和主页上显示每篇帖子是不方便的。相反,应该使用分页来每次只获取和显示一页的帖子。可以使用一些gem来实现分页,如kaminariwill_paginate,或者使用更大的管理解决方案,如ActiveAdmin。如果不喜欢页面链接,也可以找到使用"无限滚动"的示例。

最后,可以添加缓存。由于网站不会经常更新,可以在多个层次进行缓存。可以阅读Caching with Rails: An Overview了解更多信息。

但是,缓存也会带来自身的问题。在进行基本性能优化之后再考虑是否需要缓存。

另外,可以查阅"SQL EXPLAIN"。虽然OP没有说明他们使用的是MySQL、PostgreSQL还是其他数据库,但是所有数据库都有相应的EXPLAIN系统。而且,ActiveRecord通过.explain方法支持这些系统。EXPLAIN会查询数据库执行查询的计划,并指定是否使用索引。如果数据库在执行计划的某个阶段不使用索引,将出现可怕的"Table Scan"。

总之,在解决Ruby on Rails网站运行缓慢的问题时,可以通过添加SQL索引、减少对Post.all的调用、使用分页和缓存来优化性能。此外,还可以使用"SQL EXPLAIN"来查看数据库执行计划并确定是否使用索引。

0