3

ユーザーテーブルと投票テーブルがあります。投票テーブルには、他のユーザーに対する投票が格納されます。そして、良くも悪くも、votes テーブルの 1 つの行に、2 人のユーザー間の双方向の投票が格納されます。

さて、問題は、たとえば誰かが投票したすべての人をリストしたいときです。

私は MySQL の専門家ではありませんが、結合ステートメントの OR 条件のおかげで、 users テーブル全体(現在 +44,000 行) を調べる必要があり、実行する一時テーブルを作成する必要があることがわかりました。それで。

現在、次のクエリには約 2 分かかります。はい、完了までに2 分かかります。OR 条件を削除し、その後の結合ステートメントをすべて削除すると、44,000 のユーザー行のうち約 17 行を調べるだけで済むため、0.5 秒未満で実行されます (説明してください!)。

次の例では、ユーザー ID は9834で、自分投票なしをフェッチし、投票されたユーザーからの情報を結果に結合しようとしています。

このクエリを実行するためのより良い、より高速な方法はありますか? または、テーブルを再構築する必要がありますか? クエリを変更することで修正できることを真剣に願っています。テーブルには既に多くのユーザー (+44,000) と投票 (+130,000) があるため、移行する必要があります。

ありがとう :)

SELECT *, votes.id as vote_id 
FROM `votes` 
LEFT JOIN users ON (
  (
    votes.user_id_1 = 9834
    AND
    users.uid = votes.user_id_2
  )
  OR
  (
    votes.user_id_2 = 9834
    AND
    users.uid = votes.user_id_1
  )
)
WHERE (
  (
    votes.user_id_1 = 9834
    AND
    votes.vote_1 = 0
  )
  OR
  (
    votes.user_id_2 = 9834
    AND
    votes.vote_2 = 0
  )
)
ORDER BY votes.updated_at DESC
LIMIT 0, 10
4

2 に答える 2

6

ORの代わりに、2つのクエリのUNIONを実行できます。私はこれが少なくとも1つの他のDBMSで桁違いに速い例を知っています、そして私はMySQLのクエリオプティマイザが同じ「機能」を共有するかもしれないと推測しています。

SELECT  whatever
FROM    votes v
        INNER JOIN
                users u
                ON v.user_id_1 = u.uid
WHERE   v.user_id_2 = 9834
AND     v.votes_2 = 0

UNION

SELECT  whatever
FROM    votes v
        INNER JOIN
                users u
                ON v.user_id_2 = u.uid
WHERE   v.user_id_1 = 9834
AND     v.votes_1 = 0

ORDER BY updated_at DESC
于 2009-04-01T12:46:20.303 に答える
0

あなたは自分の質問に答えました: はい、テーブルを再設計する必要があります。遅すぎるし、過度に複雑なクエリが必要です。幸いなことに、データの移行は、基本的にここで質問しているクエリを実行するだけの問題ですが、1 人だけではなくすべてのユーザーを対象としています。(つまり、最初の回答で提案された和集合の合計またはカウントです。)

于 2009-04-01T23:53:01.963 に答える