1

I'v been asked to add functionality to an application that lets users vote between two options: A and B. The table for those questions is very basic:

QUESTIONS
question_id (PK)
option_id_1(FK)
option_id_2(FK)
urgent (boolean)

Each time a user votes, that the user has voted is stored in an equally simple table:

USER VOTES
vote_id (PK)
user_id (FK)
question_id (FK)

The algorithm for selecting which question appears when a user requests a new one is complex, but for our purposes we can assume it's random. So, the issue?

Each user will be voting on many questions. Likely hundreds, and possibly thousands. I need to ensure no user is presented with a question they've already voted on, and the only way I can think to do that will, I'm guessing, pound the server into oblivion. Specifically, something like:

SELECT * from questions WHERE question_id NOT in (SELECT question_id from user_votes WHERE user_id = <user_id>) ORDER BY RAND() LIMIT 1. 

[Note: RAND() is not actually in the query - it's just there as a substitute for a slightly complex (order_by).]

So, keeping in mind that many users could well have voted on hundreds if not thousands of questions, and that it's not possible to present the questions in a set order...any ideas on how to exclude voted-on questions without beating my server into the ground?

All advice appreciated - many thanks.

4

2 に答える 2

3

JOIN演算子は、MySQL のネストされたクエリよりもはるかに優れたパフォーマンスを発揮します (最新の MySQL リリースで変更された可能性がありますが、パフォーマンスの問題が発生している場合は、ステートメントがまだ保持されていると思います)

あなたができることは、投票を質問に参加させたままにし、投票が参加しなかった(誰も投票しなかった)レコードのみを選択することです。

SELECT * 
FROM questions q 
LEFT JOIN user_votes uv ON 
  uv.question_id = q.question_id AND
  uv.user_id = '<user_id>'
WHERE vote_id IS NULL
于 2012-04-19T12:51:21.103 に答える
1

RAND() は厄介ですが、これにより、必要な結果が得られながら問題が軽減される場合があります。RAND() が例であると述べたように、以下よりも具体的な提案を実際に提供することはできませんが、ORDER BY を置き換えることは問題なく機能するはずです。

内部クエリの行数を制限できるほど、クエリ全体の実行速度が向上します。

SELECT
    q.*
FROM (
    -- First get the questions which have not been answered
    SELECT 
        questions.*
    FROM questions 
    LEFT JOIN user_votes 
        ON user_votes.question_id = questions.question_id
        AND user_votes.user_id = <user_id>
    WHERE user_votes.user_id IS NULL
) q
-- Now get a random 1.  I hate RAND().
ORDER BY RAND()
LIMIT 1
于 2012-04-19T12:54:21.023 に答える