mysql limit join - есть ли более эффективный способ сделать это? - PullRequest
0 голосов
/ 26 июля 2011

У меня есть три таблицы - 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 голосов
/ 26 июля 2011

Мне кажется, что это нормально, хотя я бы немного его изменил:

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 запросить и сравнить.

0 голосов
/ 26 июля 2011

Используйте левое соединение, как это:

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;

Я изменил псевдонимы таблицы, чтобы сделать их более понятными.

0 голосов
/ 26 июля 2011

Это можно сделать немного лучше, переключив 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 много строк.Посмотрите эту презентацию Билла Карвина (слайд 142 и далее), чтобы узнать о некоторых других идеях выбора случайной строки.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...