我有一个应用程序(更可能是一个测验应用程序),我将所有 1000 个测验都保存在 MySQL 数据库中,当用户请求时,我想从该表中检索一个随机问题,我可以使用 RAND() 函数轻松完成在 MySQL 中.. 我的问题是,我不想给用户两次或多次相同的问题,我怎样才能记录检索到的问题?我必须为每个用户创建表吗?这不会增加加载时间吗?请帮助我,任何帮助将是一个很大的帮助..
-问候
如果您想在短时间内使用它,请使用用户的$_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
)
我的问题是,我不想给用户两次或多次相同的问题,我怎样才能记录检索到的问题?我必须为每个用户创建表吗?这不会增加加载时间吗?
是的,但可能没有那么多。
您保留一个额外的表格,userId, questionId
并在其中插入已经向各个用户提出的问题。
当您向用户 456 询问问题 123 时,您运行一个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)
,加入将非常有效。
在这样的表上选择不应该使用,这将在输出其中一个之前ORDER BY RAND()
检索表中的所有行。通常你会questionId
随机选择 a ,然后选择带有 that 的问题,questionId
这样会更快。但是在这里,您无法保证该用户尚未向该用户提出问题,并且更快的查询可能会失败。
当大多数问题仍然可以自由提问时,您可以使用
WHERE questions.questionId IN ( RAND(N), RAND(N), RAND(N), ... )
AND askedQuestions.userId IS NULL LIMIT 1
其中 N 是问题的数量。您提取的随机数中至少有一个可能仍然是免费的。这IN
会降低性能,您将不得不与 s 的数量取得平衡RAND
。当几乎所有问题都被问到时,匹配的机会就会减少,即使有很多RAND
s,您的查询也可能不会返回任何内容(也因为RAND
s 将开始产生重复的 ID,这就是所谓的生日悖论)。
实现两全其美的一种方法可能是确定最大尝试次数,例如 3 次(或者更好,基于剩余问题的数量)。
对于 X 次,您生成(在 PHP 中)一组 Y 随机 id 在 1 和 1000 之间,并尝试(userId, questionId)
从askedQuestions
. 该表很薄且有索引,因此速度非常快。如果失败,则提取questionId
是随机且免费的,您可以运行
SELECT * FROM questions WHERE id = {$tuple['questionId']};
这也非常快。如果您成功 X 次,即 X 次,所有 Y 个随机 questionId 都被注册为已被询问,然后您运行完整查询。大多数用户将几乎立即得到服务(两个非常快速的查询),只有少数真正敬业的用户需要更多处理。您可能希望设置某种警报来警告您用户没有问题。
一种解决方案是在问题表中添加一个ID 列,当您将其提供给用户时,您会使用您为用户提供的问题列表检查该 ID。
您可以使用内存数据结构(如List)来跟踪提供给特定用户的问题。这样,您只需要列表数组而不是表格即可完成工作。