2012-04-19 13 views
1

AとBの2つのオプションの間で投票できる機能をアプリケーションに追加するように求められました。これらの質問の表は非常に基本的です。データベース設計/ SQL最適化:WHERE <id>(何千ものID)

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

たびにユーザーの投票、投票したユーザーは均等に単純なテーブルに格納されていること:

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

ユーザーは新しいものが複雑で要求したときに質問が表示される選択するためのアルゴリズム、私たちの目的のために、それはランダムであると仮定することができます。だから、問題?

各ユーザーは多くの質問に投票します。おそらく数百、おそらく数千ユーザーには既に投票した質問は表示されないようにする必要があります。私が考えることができると思う唯一の方法は、サーバーを忘れてしまいます。具体的には、のようなもの:

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

[注:RAND()は、クエリでは、実際にはない - それはちょうどそこに少し複雑な(ORDER_BY)の代用として'S]

ので、それを念頭において多くのユーザーが何千もの質問ではなく、何千もの質問に投票することができました。また、質問をセットオーダーで提示することはできません。投票した質問をサーバーを倒すことなく除外する方法に関するアイディア

すべてのアドバイスをいただきありがとうございます。

+0

RAND()は潜在的に大きなパフォーマンスの落とし穴です。ちょうどFYI –

+0

Cheers simonです。 rand()はデモンストレーションのためだけにそこにあり、order_by [フィールドの束]です。上記で編集されました。 – PlankTon

+0

RAND()が特定の基準を見るのとは違っているのを見て:) –

答えて

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 
+0

ニースはそれを考えていませんでした。ありがとうkeymone – PlankTon

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