0

actions450,000 を超えるレコードを含むテーブルがあります。actionsテーブルにテーブルを結合したいusers(実際には、テーブルに結合する前に、他の 2 つのテーブルを結合し、そのうちの 1 つは他のテーブルに結合され、もう 1 つはテーブルに結合されusersますactions)。SQL クエリは次のようになります。

SELECT "users".* FROM "users" INNER JOIN "campaigns" ON "campaigns"."user_id" = "users"."id" INNER JOIN "books" ON "books"."campaign_id" = "campaigns"."id" INNER JOIN "actions" ON "actions"."book_id" = "books"."id" AND "actions"."type" IN ('Impression')

ただし、レールでこのクエリを実行すると、テーブル内の多数のレコードが原因でアプリがハングしactionsます。

これをどのように処理すればよいですか?

4

1 に答える 1

0

このアプローチにはいくつかの問題があります。

  1. 同じユーザーを数回フェッチしています(ユーザーにアクションの数を掛けたもの)
  2. 対応するアクションを持つすべてのユーザーを一度にフェッチしています。これは、メモリを大量に消費するため、ガベージコレクションが頻繁に発生することを意味します。
  3. ユーザーのすべての属性を取得しています。私は、あなたがそれらすべてを必要としないと思います
  4. 注文数によるユーザーの注文についてコメントしました。これをRubyコードで行いますか?はいの場合、それは4番目の問題です。大きな問題、確かに

したがって、レコードをグループ化するためにgroup()メソッドを使用するか、次のような単純なSQLを使用することを提案します。

    SELECT "users".id, count(*) as actions_cnt
    FROM "users" 
        INNER JOIN "campaigns" ON "campaigns"."user_id" = "users"."id" 
        INNER JOIN "books" ON "books"."campaign_id" = "campaigns"."id" 
        INNER JOIN "actions" ON "actions"."book_id" = "books"."id" AND "actions"."type" IN ('Impression')
    GROUP BY
        "users".id

アプリに多数のユーザーがいる場合は、「OFFSET#{offset} LIMIT#{limit}」を追加して、レコードをバッチでフェッチすることをお勧めします。

最後に、メモリフットプリントがそれほど大きくならないように、必要な列を直接指定できます。

于 2012-05-21T11:54:01.350 に答える