Mysql:知道我们不想要特定ID的数据库获取结果
我目前正在测验网站上工作。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都已经回答了,并且确定查询不会对我的服务器太难处理?
在此先感谢!
子选择
SELECT *
FROM questions
WHERE question_id NOT IN (
SELECT question_id
FROM answers
WHERE user = XX
)
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 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
WHERE子句中A“不在”应该做的伎俩:
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列表。对于每个用户,创建一个不同的种子,以便为不同的用户获得不同的问题序列。
每个用户的10个KB需要存储预先计算的1000个问题列表。这似乎不太高。但是,它会影响性能,因为在加载该字段时,数据库必须将所有额外的数据发送到应用程序。
这是一个远不那么简单的解决方案,其他答案在这里,绝对是过早的优化。不过,我想我应该建议它作为复杂SQL查询的替代方案。
如果你关心的是查询的长度,你可以缩短它的“NOT IN()”概念:http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_not -在 – Igor 2011-05-25 15:14:41