2011-05-25 49 views
2

我目前正在测验网站上工作。Mysql:知道我们不想要特定ID的数据库获取结果

我有一个约数据库。 1000个问题 - 但数据库将逐周增长。

每天,玩这个测验的每个用户都会随机得到5个问题。

问题是我不希望单个用户在两个不同的日期得到相同的问题2次。

我存储的用户的所有回答问题的历史,这样我就可以知道用户ID:1已经回答了答案ID:4质疑ID:6日期YYYY-MM-DD

基本上:

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 

OR(容易)

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,查询会杀死我的服务器,不是吗?

有没有什么办法让我为我的用户随机获得5个问题,因为我知道问题的所有ID都已经回答了,并且确定查询不会对我的服务器太难处理?

在此先感谢!

+0

如果你关心的是查询的长度,你可以缩短它的“NOT IN()”概念:http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_not -在 – Igor 2011-05-25 15:14:41

回答

0

子选择

SELECT * 
FROM questions 
WHERE question_id NOT IN (
    SELECT question_id 
    FROM answers 
    WHERE user = XX 
) 
1

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 
0

是的,你可以有一个等效NOT IN查询与NOT EXISTS

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

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

WHERE子句中A“不在”应该做的伎俩:

SELECT 
    XYZ 
FROM 
    QUESTIONS 
WHERE 
    ID NOT IN (SELECT ID FROM QUESTION_HISTORY WHERE USER_ID = @USERID) 
0

我建议你使用多个查询此为“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'); 

我想这应该跑得更快,但它可能会更好进行基准测试,而不是妄加猜测。

0

到目前为止,所有建议都涉及在数据库上运行相当昂贵的查询。如果你有很多用户和很多问题,你可能会遇到性能问题。如果这是一个问题,您可以选择存储复杂性而不是时​​间复杂度:

警告:提前进行不成熟优化!

对于每个用户,预先生成问题ID的随机排列的集合。在应用程序代码中执行此操作,并将其作为Blob存储到数据库中。还要为每个用户存储他们在该列表中的位置。现在您只需加载列表,跳到正确的位置,然后返回相关问题。

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

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

这是一个远不那么简单的解决方案,其他答案在这里,绝对是过早的优化。不过,我想我应该建议它作为复杂SQL查询的替代方案。

相关问题