各グループから上位 X の結果を取得するより効率的な方法はありますか?
クエリで使用されていない sqlfiddle のフィールドは無視できます。
クエリ:
SET @num := 0, @item_id := '';
SELECT `item_id`, `user_id`, total_hoarded FROM (
SELECT `item_id`, `user_id`, total_hoarded,
@num := IF(@item_id = x.`item_id`, @num + 1, 1) AS ROW_NUMBER,
@item_id := x.`item_id` AS dummy
FROM (
SELECT `item_id`, `user_id`, COUNT(*) AS total_hoarded
FROM `player_items`
GROUP BY `item_id`, `user_id`
ORDER BY `item_id`, total_hoarded DESC
) AS x
) AS y WHERE y.ROW_NUMBER <= 10;");
デモ: http://sqlfiddle.com/#!2/75bc7/1
クエリの説明:
(最もネストされたクエリから開始) item_id と user_id ですべての行を取得してグループ化し、集計関数を実行して各ユーザーが持っているアイテムの数を把握できるようにします。
次のレベルでは、各行に row_number をアタッチします。これにより、最終的なクエリで、X 未満のすべての行 (この場合は、各グループの上位 10 人のユーザー) を単純に取得できます。
SQLFiddle は、サンプルのサイズに制限があるため、2 つのアイテムと少数のユーザーのデータのみを表示します。トップ 10 を完全に埋めるには十分ではありませんが、私が何をしているかを示すには十分です。
オプション(検討中):
- クエリはそのままにしておきます。
- 標準的なクエリのグループ化を行い、PHP をループして上位 10 件を取得します。
- 他の?(他は考えていません)
注:
十分な詳細を提供していない可能性があることは承知していますので、必要なものをお知らせください。私はこれにアプローチするための一般的な方法を見ているだけです。上記のクエリは、3,000 万行のテーブルで実行するのに約 5 分かかります。ただし、クエリは 1 時間に 1 回しか実行されないため、これは大したことではありません。
クエリを小さな部分に分割すると、実行速度が向上する可能性がありますが、テーブルが大量に書き込まれるため、クエリがロックアウトされる傾向があります。