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

Mat*_*ieu 7 ruby activerecord ruby-on-rails devise ruby-on-rails-4

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

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

这是迁移

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
Run Code Online (Sandbox Code Playgroud)

当用户加载一个Deal(例如Deal id = 4)时,我使用一个名为的方法 show

controllers/deal.rb
#for the view of the Deal page
def show
end
Run Code Online (Sandbox Code Playgroud)

在这个Deal id = 4页面的视图中,我需要current_user 在用户当前所在的Deal页面中显示Devise的视图.

deal/show.html

here is the nb of views of user: <% current_user.#{deal_id}.nb_views%>
Run Code Online (Sandbox Code Playgroud)

让我们说我有10M + user_deals线,我想知道我是否应该使用索引

add_index :user_deals, :user_id
add_index :user_deals, :deal_id
Run Code Online (Sandbox Code Playgroud)

或者可能

add_index(:deals, [:user_id, deal_id])
Run Code Online (Sandbox Code Playgroud)

确实在其他情况下我会说是,但在这里我不知道Rails如何在幕后工作.感觉好像Rails是知道的,而不需要我来加快这一进程,......该怎么办,就好像当Rails的负载这种观点是没有SQL查询(如"找到的意见处,NB user_id= xdeal_id= Y"). ...因为我只是用于current_user登录的人(通过设计current_user)并且deal_idRails知道它,因为我们在这个交易的页面(显示页面)所以我只是将它作为参数传递.

那么我需要一个索引来加速它吗?

Ada*_*ish 5

你关于索引的问题是一个很好的问题。导轨确实会生成 SQL* 来发挥其魔力,因此优化数据库的常规规则适用。

devise 的魔力仅适用于 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
Run Code Online (Sandbox Code Playgroud)

您会注意到迁移包括两个索引。如果您从未期望为给定交易创建所有用户的视图,那么您将不需要这些索引中的第二个。然而,正如 @chiptuned 所说,对每个外键建立索引几乎总是正确的选择。整数索引只消耗很少的写入资源,但在读取方面却节省了大量资源。这是一个成本非常低的默认防御位置。

如果您将数据获取逻辑放入控制器中,您将会度过一段更好的时光,并且事情会感觉更清晰。此外,您正在展示一项交易,因此您会觉得这样做是正确的,而不是current_user,因此将其作为数据获取的中心

实际上,您可以在不使用through关联的情况下执行此查询,因为您可以在不接触用户表的情况下执行此查询。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
Run Code Online (Sandbox Code Playgroud)

那么在你看来...

I can get info about the deal: <%= @deal.description %>
Run Code Online (Sandbox Code Playgroud)

并感谢includes我可以获取用户 nb_views 而无需单独的 SQL 查询: <%= @deal.user_deals.nb_views %>

* 如果你想看看 SQL Rails 神奇地生成了什么,就放在.to_sql最后。例如sql_string = current_user.deals.to_sql@deal.to_sql