2

特定の種類の記事の数を把握しようとしています。私は非常に非効率的なクエリを持っています:

Article.where(status: 'Finished').select{|x| x.tags & Article::EXPERT_TAGS}.size

より優れたプログラマーになるための探求において、これをより高速なクエリにする方法を考えています。tagsは の文字列の配列でArticleArticle::EXPERT_TAGSは別の文字列の配列です。配列の交点を見つけて、結果のレコード数を取得したいと考えています。

EDIT:Mongo配列として定義されていますArticle::EXPERT_TAGSarticle.tagsこれらの配列は文字列を保持しており、シリアライズされた文字列だと思います。例: Article.first.tags = ["Guest Writer", "News Article", "Press Release"]. 残念ながら、これはタグの別のテーブルとして適切に設定されていません。

2番目の編集:私はMongoDBを使用しているので、実際にはActiveRecordではなく、MongoMapperやmo​​ngoidのようなMongoWrapperを使用しています。これは私のミスです、ごめんなさい!このエラーのため、この質問の分析が台無しになります。エラーを指摘してくれた PinnyM に感謝します。

4

3 に答える 3

0

tagsリスト全体が 1 つのデータベース フィールドに保存され、それを維持したいと仮定すると、処理のためにすべてのデータを Ruby に取り込む必要があるため、改善の余地はあまりありません。

ただし、データベース クエリには 1 つの問題があります。

Article.where(status: 'Finished')

# This translates into the following query
SELECT * FROM articles WHERE status = 'Finished'

基本的に、すべての列をフェッチしていますがtags、プロセスには列のみが必要です。pluckしたがって、次のように使用できます。

Article.where(status: 'Finished').pluck(:tags)

# This translates into the following query
SELECT tags FROM articles WHERE status = 'Finished'
于 2013-09-16T15:29:35.480 に答える
0

ここで ActiveRecord のクエリのような一般的な交差に関する質問に答えました。

以下抜粋:


以下は、ActiveRecord で交差のようなクエリを構築するために使用する一般的なアプローチです。

class Service < ActiveRecord::Base
  belongs_to :person

  def self.with_types(*types)
    where(service_type: types)
  end
end

class City < ActiveRecord::Base
  has_and_belongs_to_many :services
  has_many :people, inverse_of: :city
end

class Person < ActiveRecord::Base
  belongs_to :city, inverse_of: :people

  def self.with_cities(cities)
    where(city_id: cities)
  end

  # intersection like query
  def self.with_all_service_types(*types)
    types.map { |t|
      joins(:services).merge(Service.with_types t).select(:id)
    }.reduce(scoped) { |scope, subquery|
      scope.where(id: subquery)
    }
  end
end

Person.with_all_service_types(1, 2)
Person.with_all_service_types(1, 2).with_cities(City.where(name: 'Gold Coast'))

次の形式の SQL が生成されます。

SELECT "people".*
  FROM "people"
 WHERE "people"."id" in (SELECT "people"."id" FROM ...)
   AND "people"."id" in (SELECT ...)
   AND ...

各サブクエリが結果セットで一致する人物の ID を返す限り、条件/結合などに基づいて上記のアプローチで必要な数のサブクエリを作成できます。

各サブクエリの結果セットは AND で結合されるため、一致するセットがすべてのサブクエリの共通部分に制限されます。

于 2013-09-16T15:44:32.990 に答える