0

ユーザーのデータベースと、ユーザーに属するfacebook_accountsがあります。ユーザーは、他のユーザーと比較したポイント数によって「ランク付け」されます。これは、そのユーザーよりも多くのポイントを持つすべてのユーザーをカウントする埋め込み SELECT ステートメントを使用して行われます。

データベースには最大 10,000 人のユーザーがいます。次の SQL クエリは、MySQL が完了するまでに ~0.16 秒かかります。

SELECT
    *, (SELECT (COUNT(*) + 1)
            FROM users AS UserHigher
            WHERE UserHigher.points > User.points
       ) AS rank
FROM
    users AS User
ORDER BY
    User.points DESC, User.created ASC
LIMIT 0, 30

ただし、LEFT JOIN を追加してユーザーのfacebook_accountも取得すると、 MySQL がハングします。

SELECT
    *, (SELECT (COUNT(*) + 1)
            FROM users AS UserHigher
            WHERE UserHigher.points > User.points
       ) AS rank
FROM
    users AS User
LEFT JOIN
    facebook_accounts AS FacebookAccount
        ON (FacebookAccount.user_id = User.id)
ORDER BY
    User.points DESC, User.created ASC
LIMIT 0, 30

ユーザーをランク付けするための COUNT() 選択方法がやや非効率的であることは理解していますが、これは私が遭遇した中で最も信頼できる方法です。私が理解していないのは、単純な LEFT JOIN が、ランキングの SELECT ステートメントとは完全に分離しているように見えるときに、そうでなければ合理的なクエリを破壊する理由です。

何かアドバイス?

4

1 に答える 1

1

私の推測では、元のクエリは最初に順序付けを行い、ランクは30回しか実行されません。2番目のクエリは、MySQLがこの最適化を検出するには複雑すぎます。

以下が役立つかもしれません:

select *
from (SELECT *, (SELECT (COUNT(*) + 1)
                 FROM users AS UserHigher
                 WHERE UserHigher.points > User.points
                ) AS rank
      FROM users AS User
      ORDER BY User.points DESC, User.created ASC
      LIMIT 0, 30
     ) t join
     facebook_accounts AS FacebookAccount
     ON (FacebookAccount.user_id = User.id)
order by points desc, created asc
于 2013-02-23T00:27:52.427 に答える