0

私は次のように2つの関係を持っています:

class CfThread < ActiveRecord::Base
  self.primary_key = 'thread_id'
  self.table_name  = 'cforum.threads'

  belongs_to :forum, class_name: 'CfForum', :foreign_key => :forum_id
  has_many :messages, class_name: 'CfMessage', :foreign_key => :thread_id

  attr_accessible :thread_id, :tid, :slug, :forum_id, :archived, :created_at, :updated_at
end

class CfMessage < ActiveRecord::Base
  has_one :owner, class_name: 'CfUser', :foreign_key => :user_id
  has_many :flags, class_name: 'CfFlag'

  belongs_to :thread, class_name: 'CfThread', :foreign_key => :thread_id

  attr_accessible :message_id, :mid, :thread_id, :subject, :content,
    :author, :email, :homepage, :deleted, :user_id, :parent_id,
    :updated_at, :created_at
end

n + 1クエリの状況を生成せずに、最後の10スレッドとそのメッセージをクエリしたいと思います。

@threads = CfThread.includes(:messages).order('cforum.threads.created_at DESC').limit(10)

これにより、DISTINCTを使用して非常に遅いクエリが生成されます。

SELECT DISTINCT "cforum"."threads".thread_id, cforum.threads.created_at AS alias_0 FROM "cforum"."threads" LEFT OUTER JOIN "cforum"."messages" ON "cforum"."messages"."thread_id" = "cforum"."threads"."thread_id" ORDER BY cforum.threads.created_at DESC LIMIT 10

クエリプランナーは、スレッドとメッセージに対して全表スキャンを実行したいと考えています。

プレーンSQLを使用すると、この状況を最適化するのは非常に簡単ですが、ARを使用する方法もありますか?n + 1クエリを生成せずにDISTINCTを回避できますか?

ご挨拶、CK

編集:インデックスは次のように与えられます:

スレッド:

"threads_pkey" PRIMARY KEY, btree (thread_id)
"index_cforum.threads_on_slug" UNIQUE, btree (slug)
"index_cforum.threads_on_archived" btree (archived)
"index_cforum.threads_on_tid" btree (tid)
"threads_created_at_idx" btree (created_at, updated_at)

メッセージ:

"messages_pkey" PRIMARY KEY, btree (message_id)
"index_cforum.messages_on_mid" btree (mid)
"index_cforum.messages_on_thread_id" btree (thread_id)
4

1 に答える 1

2

あなたの注文はアクティブレコードを少し混乱させていると思います-アクティブレコードは、注文が機能するために結合された列が必要だと考えていると思います。したがって、結合ベースの include バリアントを使用しているため、制限したい場合は個別のクエリが必要になります。

明らかに、順序は CfThread モデルのみに依存します。混乱しているのは AR ヒューリスティックだけです。1 つの方法は、次のようにして使用されるイーガー ロード モードを強制することです。

CfThread.preload(:messages).order('cforum.threads.created_at DESC').limit(10)
于 2012-07-04T13:39:54.947 に答える