我应该如何使用Rails索引和查询连接表?

时间:2015-11-26 19:48:13

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord devise

我在Rails 4应用程序上有一个ruby,使用设计,用户模型和交易模型。

我正在为User和Deal之间的has_many / has_many关系创建一个user_deals表。

这是迁移

class CreateUserDeals < ActiveRecord::Migration

  def change
    create_table :user_deals do |t|
        t.belongs_to :user
      t.belongs_to :deal
      t.integer         :nb_views

      t.timestamps
    end
  end
end

当用户加载交易时(例如,交易ID = 4),我使用名为show的方法

controllers/deal.rb
#for the view of the Deal page
def show
end

在此Deal = 4页面的视图中,我需要在用户当前所在的“交易”页面中显示设计current_user 的nb个观看次数

deal/show.html

here is the nb of views of user: <% current_user.#{deal_id}.nb_views%>

允许&#39;说我有10M + user_deals行,我想知道我是否应该使用索引

add_index :user_deals, :user_id
add_index :user_deals, :deal_id

或者

add_index(:deals, [:user_id, deal_id])

确实在其他情况下我会说是,但在这里我不知道Rails如何在幕后工作。感觉好像Rails在没有我需要加速进程的情况下知道该怎么做,就好像当Rails加载这个视图时没有SQL查询(例如&#39;找到视图的nb WHERe { {1}}和user_id= x&#39;)....因为我只使用登录的deal_id= Y(通过设计{{1} }和current_user Rails知道它,因为我们在这个交易的页面(显示页面),所以我只是将它作为参数传递。

所以我需要一个索引来加速它吗?

3 个答案:

答案 0 :(得分:4)

关于索引的问题很好。 Rails 确实生成SQL *以实现其魔力,因此优化数据库的常规规则适用。

设计的魔力只延伸到current_user。它使用SQL查询获取其详细信息,这是有效的,因为默认情况下由devise创建的用户表具有有用的索引。但这些并不是你需要的指标。

首先,有一种更为惯用的方式来做你以后的事情

class CreateUserDeals < ActiveRecord::Migration
  def change
    create_join_table :users, :deals do |t|
      t.integer :nb_views
      t.index [:user_id, :deal_id]
      t.index [:deal_id, :user_id]
      t.timestamps
    end
  end
end

您会注意到迁移包含两个索引。如果您从未期望为给定的交易创建所有用户的视图,那么您将不再需要这些索引中的第二个。但是,正如@chiptuned所说,索引每个外键几乎总是正确的。整数的索引会花费很少的写入资源,但会大大节省读取费用。这是一个非常低成本的默认防守阵地。

如果您将数据提取逻辑放在控制器中,您将拥有更好的时间并且事情会更加清晰。此外,您正在显示交易,因此您应该做到这一点而不是current_user获取数据的中心。

您实际上可以在不使用through关联的情况下执行此查询,因为您可以在不触及users表的情况下执行此操作。 (尽管如此,您可能希望through关联到其他情况。) 只需has_many :user_deals即可完成此任务。

为了最好地利用数据库引擎并在一个查询中执行此操作,您的控制器可能如下所示:

def show
  @deal = Deal.includes(:user_deals)
              .joins(:user_deals)
              .where("user_deals.user_id = ?", current_user.id)
              .find(params["deal_id"])
end

然后在你看来......

I can get info about the deal: <%= @deal.description %>

感谢includes我可以在没有单独的SQL查询的情况下获取用户nb_views:     &lt;%= @ deal.user_deals.nb_views%&gt;

*如果你想看看哪些SQL rails神奇地生成了最后只放.to_sql。例如sql_string = current_user.deals.to_sql@deal.to_sql

答案 1 :(得分:1)

是的,您应该使用索引来加速查询user_deals记录。绝对至少在user_id上,但可能正如你所说的那样[:user_id, :deal_id]

至于为什么你没有看到SQL查询......

首先,视图中的代码似乎不正确。假设您在has_many :deals, through: :user_deals课程中设置了User关联,则应该类似于:

here is the nb of views of user: <%= current_user.deals.find(deal_id).nb_views %>

如果您看到显示nb_views的正确数字,那么在呈现视图时应该进行查询,除非在处理过程中已经加载current_user.deals或者您已经加载了android-async-http:1.4.9某种缓存正在进行中。

如果Rails意识到&#34;,那么你应该弄清楚它背后的某种原因。预期的基本Rails行为是在那里发布SQL查询。

答案 2 :(得分:1)

是一种更简洁的方法来索引其他表格:

class CreateUserDeals < ActiveRecord::Migration

   def change
      create_table :user_deals do |t|
         t.references :user
         t.references :deal
         t.integer :nb_views

         t.timestamps
      end
   end
end