mysql限制连接 - 有更有效的方法吗?

时间:2011-07-26 11:52:10

标签: mysql join random limit

我有三个表 - tblpollquestions,tblpollanswers和tblpollresponses。

我想选择一个用户尚未回复的随机问题,并附上相应的答案。

下面的SQL完全返回我需要的内容,但我担心需要三个SELECT才能完成。肯定有更有效的方法吗?

SELECT
    poll.id,
    poll.question,
    a.answer
FROM tblpollquestions poll
INNER JOIN tblpollanswers a ON a.question_id = poll.id
INNER JOIN (
    SELECT id FROM tblpollquestions WHERE id NOT IN(
        SELECT question_id FROM tblpollresponses WHERE user_id = 1
    ) ORDER BY RAND() LIMIT 1
) as t ON t.id = poll.id

3 个答案:

答案 0 :(得分:0)

NOT IN(SELECT...)切换为LEFT JOIN

,可以做得更好
SELECT
    poll.id,
    poll.question,
    a.answer
FROM 
    tblpollquestions poll
INNER JOIN 
    tblpollanswers a 
ON 
    a.question_id = poll.id
INNER JOIN (
    SELECT 
        q.id 
    FROM 
        tblpollquestions AS q
    LEFT JOIN
        tblpollresponses AS r
    ON
        q.id = r.question_id
        AND r.user_id = 1
    WHERE
        r.question_id IS NULL
    ORDER BY RAND() LIMIT 1
) as t ON t.id = poll.id
如果ORDER BY RAND()表中有很多行,

tblpollquestions也会很慢。有关选择随机行的其他一些想法,请参阅Bill Karwin的演示文稿(幻灯片142及其后)。

http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back

答案 1 :(得分:0)

对我来说似乎很好,虽然我会稍微改变一下:

SELECT
  poll.id,
  poll.question,
  a.answer
FROM tblpollquestions poll
INNER JOIN tblpollanswers a ON a.question_id = poll.id
WHERE poll.id = (
    SELECT id FROM tblpollquestions WHERE NOT EXISTS (
        SELECT * FROM tblpollresponses WHERE user_id = 1 AND question_id = tblpollquestions.id )
    ORDER BY RAND() LIMIT 1)

以这种方式编写应该更好地使用索引,而不是检查每个tblpollanswers的连接条件。

确保确定 UNIQUE tblpollresponses上的(user_id, question_id)索引(或主键)(按此顺序)。如果您需要其他查询,则可以按相反顺序添加其他UNIQUE索引。

编辑:实际上将它放在可能不太好的地方http://jan.kneschke.de/projects/mysql/order-by-rand/您需要explain查询并进行比较。

答案 2 :(得分:0)

像这样使用左连接:

SELECT ques.id, ques.question, ans.answer FROM tblpollquestions ques
INNER JOIN tblpollanswers ans ON(ans.question_id = ques.id)
left join tblpollresponses res on(res.question_id=ques.id and user_id = 1)
where res.question_id is null ORDER BY RAND() LIMIT 1;

我更改了表别名,以便更好地理解。