3

1000 個のクイズをすべて MySQL データベースに保存したアプリケーション (クイズ アプリの可能性が高い) があります。ユーザーが質問を要求したときに、このテーブルからランダムな質問を取得したいのですが、RAND() 関数を使用して簡単に実行できます。 MySQL.. 私の問題は、ユーザーに同じ質問を 2 回以上与えたくないのですが、取得した質問の記録をどのように保持できますか? すべてのユーザーごとにテーブルを作成する必要がありますか? ロード時間が長くなりませんか??私を助けてください、どんな助けも大きな恩恵になるでしょう..

-よろしく

4

3 に答える 3

3

私の問題は、ユーザーに同じ質問を 2 回以上行いたくないのですが、取得した質問の記録をどのように保持できますか? すべてのユーザーごとにテーブルを作成する必要がありますか? ロード時間が長くなりませんか?

はい、しかしおそらくそれほどではありません。

1 つの余分なテーブルを保持userId, questionIdし、さまざまなユーザーに既に尋ねられた質問をそこに挿入します。

質問 123 をユーザー 456 に尋ねると、単一の質問を実行します。INSERT

INSERT INTO askedQuestions (userId, questionId) VALUES (456, 123);

次に、から質問を抽出questionsしますLEFT JOIN

SELECT questions.* FROM questions
    LEFT JOIN askedQuestions ON (questions.id = askedQuestions.questionId AND askedQuestions.userId = {$_SESSION['userId']} )
    WHERE askedQuestions.userId IS NULL
    ORDER BY RAND() LIMIT 1;

askedQuestionsに索引付けしておくと(userId, questionId)、結合が非常に効率的になります。

RAND()に関する注意事項

このようなテーブルでの選択は、 で行うべきではありません。これは、テーブル内のすべての行ORDER BY RAND()を取得してから、それらの 1 つを出力します。通常、ランダムに を選択し、それで質問を選択します。そのほうがはるかに高速です。しかし、ここでは、質問がまだそのユーザーに尋ねられていないという保証はなく、より高速なクエリは失敗する可能性があります。questionIdquestionId

ほとんどの質問がまだ自由にできる場合は、

WHERE questions.questionId IN ( RAND(N), RAND(N), RAND(N), ... )
  AND askedQuestions.userId IS NULL LIMIT 1

ここで、N は質問の数です。抽出した乱数の少なくとも 1 つがまだ空いている可能性があります。はINパフォーマンスが低下するため、 の数とのバランスを取る必要がありますRAND。ほとんどすべての質問が行われると、一致する可能性が低くなり、多くの s を使用してもクエリが何も返さない可能性がありますRAND(また、 s が重複した ID を生成し始めるため、これは誕生日のパラドックスRANDとして知られています)。

両方の長所を活かす方法の 1 つは、最大試行回数を 3 回に固定することです (または、残っている質問の数に基づいて、さらに良い方法です)。

X 回、(PHP で) 1 から 1000 までの Y 個のランダム ID のセットを生成し、から取得しようとし(userId, questionId)ますaskedQuestions。テーブルはシンでインデックス付けされているため、これは非常に高速です。失敗した場合、抽出されたquestionIdものはランダムで無料であり、実行できます

SELECT * FROM questions WHERE id = {$tuple['questionId']};

これも非常に高速です。X 回、つまり X 回成功した場合、すべての Y 個のランダムな questionId が既に質問されているものとして登録され、完全なクエリを実行します。ほとんどのユーザーはほぼ瞬時に処理され (2 つの非常に高速なクエリ)、少数の本当に熱心なユーザーだけがより多くの処理を必要とします。ユーザーが質問を使い果たしたことを警告するために、ある種の警告を設定することができます。

于 2012-12-23T10:46:03.150 に答える
3

短時間だけ使用したい場合は、そのためのユーザーを使用$_SESSIONしてください。

長期的に必要な場合 (同じ質問をするのではなく、明日など) -usersToQuestionsユーザー ID とユーザーが既に尋ねた質問を格納する追加のテーブルを作成する必要があります。

どちらの場合も質問を取得するには、単純な IN 条件が必要です。

SELECT * FROM questions 
WHERE id not IN  ('implode(",", $_SESSION["asked"])')

SELECT * FROM questions 
WHERE id not IN  ( 
    SELECT question_id FROM questions2users WHERE userid = 123
)
于 2012-12-23T10:42:33.420 に答える
0

1 つの解決策は、質問テーブルにID 列を追加し、それをユーザーに提供するときに、ユーザーに提供した質問のリストでその ID を確認することです。

Listのようなメモリ内データ構造を使用して、特定のユーザーに提供される質問を追跡できます。このように、テーブルの代わりにリストの配列だけが必要です。

于 2012-12-23T10:48:32.183 に答える