Mysql:从DB获取结果,知道我们不想获取特定的ID

Mysql:从DB获取结果,知道我们不想获取特定的ID,mysql,Mysql,我目前正在一个测验网站上工作 我有一个大约1000个问题的数据库-但数据库将每周增加 每天,每个参加测验的用户将随机获得5个问题 问题是我不希望一个用户在两个不同的日期内两次问同一个问题 我正在存储用户回答的所有问题的历史记录,因此我可以知道用户id:1已在YYYY-MM-DD日期将答案id:4回答为问题id:6 基本上: entry_id | user_id | question_id | answer_id | good | date 因此,当我随机向用户提出5个问题时,我有两个选择: S

我目前正在一个测验网站上工作

我有一个大约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)
我的问题是:

假设我的用户在100天的活动中已经回答了500个问题。我要问他新问题的时间非常长

... NOT IT({huge list of ids for which the user has already answered})

我担心的是,随着时间的推移,我的查询可能会变得极其缓慢。想象一个用户,我必须为他回答5个问题,知道他已经回答了5000个问题,这个查询会杀死我的服务器,不是吗

我知道所有问题的ID都已回答,并且确保我的服务器不会太难处理查询,有没有办法为我的用户随机获取5个问题

提前谢谢

子选择

SELECT *
FROM questions
WHERE question_id NOT IN (
    SELECT question_id
    FROM answers
    WHERE user = XX
)
在这种情况下,“不存在”可能会更好地为您服务

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查询中的等效项

MySQL“从外到内”评估查询,也就是说,它首先获取外部表达式outer_expr的值,然后运行子查询并捕获它生成的行

一个非常有用的优化是“通知”子查询,唯一感兴趣的行是那些内部表达式internal_expr等于outer_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)

我建议您对此使用多个查询,因为对于大型表,按兰德排序的速度非常慢

首先选择所有可能的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存储到数据库中。还为每个用户存储他们在该列表中的位置。现在你所要做的就是加载列表,跳转到正确的位置,然后返回相关的问题

您可以使用伪随机数生成算法,例如生成问题ID列表。对于每个用户,创建不同的种子,以便为不同的用户获得不同的问题序列

存储1000个问题的预先计算列表所需的每个用户10 KB。这似乎不太高。但是,它确实会影响性能,因为在加载该字段时,数据库必须将所有额外数据发送到应用程序


这是一个远不如其他人在这里回答的简单的解决方案,而且肯定是过早的优化。尽管如此,我还是认为应该建议将其作为复杂SQL查询的替代方案。

如果您关心的是查询的长度,则可以缩短查询的长度,而不是在概念上:
SELECT q.question_id, ...
    FROM questions q
    WHERE q.question_id IN ('id1', 'id2', 'id3', 'id4', 'id5');