问题描述
||
我目前在测验网站上工作。
我有大约一个数据库。 1000个问题-但是数据库将一周又一周地增长。
每天,每个参加测验的用户都会随机获得5个问题。
问题是我不希望单个用户在两个不同的日期中两次遇到相同的问题。
我正在存储用户回答的所有问题的历史记录,因此我可以知道用户ID:1已于日期YYYY-MM-DD回答了问题ID:4至问题ID:6
基本上:
entry_id | user_id | question_id | answer_id | good | date
因此,当我为用户随机获得5个问题时,我有两个选择:
SELECT question,question_id FROM questions WHERE question_id != \'X\' AND question_id != \'Y\' AND question_id != \'Z\' ORDER BY RAND() LIMIT 0,5
或(更容易)
SELECT question,question_id FROM questions WHERE question_id NOT IN(X,Y,Z)
我的问题 :
假设到目前为止,我的用户已经回答了500个问题(活动100天)。我询问他新问题的时间将非常长
... NOT IT({huge list of ids for which the user has already answered})
要么
... question_id != \'A\' AND question_id != \'B\' and so on and so on.
我担心的是,随着时间的流逝,我的查询可能会变得非常缓慢。想象一个用户,我必须回答5个问题,知道他已经回答了5000个问题,查询将杀死我的服务器,不是吗?
有什么办法让我知道用户已经回答了所有问题的ID,并确保查询不会太麻烦以至于无法为我的服务器处理,从而为用户随机获得5个问题?
提前致谢!
解决方法
在这种情况下,
NOT EXISTS
可能会更好地为您服务。
SELECT q.question,q.question_id
FROM questions q
WHERE NOT EXISTS(SELECT NULL
FROM answers a
WHERE a.question_id = q.question_id
AND a.user_id = \'YourUser\')
ORDER BY RAND() LIMIT 0,5
,是的,您可以使用与NOT EXISTS
相同的NOT IN
查询。
MySQL“从外部到内部”评估查询。也就是说,它首先获取外部表达式external_expr的值,然后运行子查询并捕获其产生的行。
一个非常有用的优化是“通知”子查询仅感兴趣的行是那些内部表达式inner_expr等于external_expr的行。这是通过将适当的等式推入子查询的WHERE子句中来完成的。也就是说,比较将转换为以下形式:
EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)
转换后,MySQL可以使用下推式相等性来限制评估子查询时必须检查的行数:
SELECT q.* FROM questions q WHERE
NOT EXISTS(SELECT 1 FROM answers a
WHERE a.question_id = q.question_id
AND a.user_id = \'UserId\')
ORDER BY RAND() LIMIT 0,5
,WHERE子句中的'NOT IN \'应该可以解决问题:
SELECT
XYZ
FROM
QUESTIONS
WHERE
ID NOT IN (SELECT ID FROM QUESTION_HISTORY WHERE USER_ID = @USERID)
,我建议您对此使用多个查询,因为对于大型表,“ ORDER BY RAND()\”相当慢。
首先选择所有可能的ID
SELECT q.question_id
FROM questions q
WHERE q.question_id NOT IN
( SELECT a.question_id
FROM anwered a
WHERE a.question_id = q.question_id AND a.user_id = \'userID\'
)
然后,您将用自己喜欢的语言选择五个随机元素,然后进行另一个查询
SELECT q.question_id,...
FROM questions q
WHERE q.question_id IN (\'id1\',\'id2\',\'id3\',\'id4\',\'id5\');
我认为这应该运行得更快,但是比起疯狂的猜测来进行基准测试可能更好。
,到目前为止,所有建议都涉及在数据库上运行相当昂贵的查询。如果您有许多用户和许多问题,则可能会遇到性能问题。如果这是一个问题,您可以选择存储复杂性而不是时间复杂性:
警告:提前优化!
对于每个用户,预先生成一个随机排序的问题ID集。在您的应用程序代码中执行此操作,并将其作为Blob存储到数据库中。还为每个用户存储他们在该列表中的位置。现在,您要做的就是加载列表,跳转到正确的位置,然后返回相关问题。
您可以使用伪随机数生成算法(例如Mersenne twister)来生成问题ID列表。为每个用户创建一个不同的种子,以便为不同的用户获得不同的问题序列。
存储预先计算的1000个问题列表时,每个用户需要10 KB。好像不太高。但是,这确实会影响您的性能,因为在加载该字段时数据库必须将所有这些额外数据发送到您的应用程序。
这是一个远远不如其他人在这里回答的简单解决方案,并且绝对是过早的优化。不过,我认为我建议将其作为复杂SQL查询的替代方法。
,子选择
SELECT *
FROM questions
WHERE question_id NOT IN (
SELECT question_id
FROM answers
WHERE user = XX
)