поиск ближайшей даты из нескольких таблиц mysql

У меня есть много таблиц, которые регистрируют действия пользователей на каком-то форуме, каждое событие журнала имеет свою дату. Мне нужен запрос, который даст мне всех пользователей, которые не были активны в течение последнего года. У меня есть следующий запрос (рабочий запрос):

SELECT *
FROM (questions AS q
    INNER JOIN Answers AS a
    INNER JOIN bestAnswerByPoll AS p
    INNER JOIN answerThumbRank AS t
    INNER JOIN notes AS n
    INNER JOIN interestingQuestion AS i ON q.user_id = a.user_id
    AND a.user_id = p.user_id
    AND p.user_id = t.user_id
    AND t.user_id = n.user_id
    AND n.user_id = i.user_id)
WHERE DATEDIFF(CURDATE(),q.date)>365
    AND DATEDIFF(CURDATE(),a.date)>365
    AND DATEDIFF(CURDATE(),p.date)>365
    AND DATEDIFF(CURDATE(),t.date)>365
    AND DATEDIFF(CURDATE(),n.date)>365
    AND DATEDIFF(CURDATE(),i.date)>365

что я делаю в этом запросе - объединяю все таблицы в соответствии с userId, а затем проверяю каждый столбец даты по отдельности, чтобы узнать, прошло ли больше года

Мне было интересно, есть ли способ сделать это проще, например, найти максимум между всеми датами (последняя дата) и сравнить только эту с текущей датой.


person Shai Zarzewski    schedule 27.04.2013    source источник
comment
прочитайте о UNION вместо JOIN, также научитесь форматировать свой код, чтобы он был читабельным с минимальными усилиями со стороны читателей, так как этот кусок беспорядка не стоит анализировать, чтобы дать полный реальный ответ! Никто не будет прилагать к ответу больше усилий, чем вы приложили к своему вопросу, на данный момент это очень мало.   -  person    schedule 27.04.2013


Ответы (2)


Если вы хотите получить максимальную производительность, вы не можете использовать greatest(). Вместо этого сделайте что-то вроде этого:

SELECT *
FROM questions q
JOIN Answers             a  ON q.user_id = a.user_id
JOIN bestAnswerByPoll    p  ON a.user_id = p.user_id
JOIN answerThumbRank     t  ON p.user_id = t.user_id
JOIN notes               n  ON t.user_id = n.user_id
JOIN interestingQuestion i  ON n.user_id = i.user_id
WHERE q.date > curdate() - interval 1 year
  AND a.date > curdate() - interval 1 year
  AND p.date > curdate() - interval 1 year
  AND t.date > curdate() - interval 1 year
  AND n.date > curdate() - interval 1 year
  AND i.date > curdate() - interval 1 year

Вы хотите избежать datediff(), чтобы MySQL мог выполнять поиск по индексу при сравнении столбцов даты. Теперь, чтобы убедиться, что поиск по индексу работает, вы должны создать составной (многостолбцовый) индекс на (user_id, date) для каждой из ваших таблиц.

В этом составном индексе первая часть (user_id) будет использоваться пользователем для более быстрого соединения, а вторая часть (date) будет использоваться для более быстрого сравнения дат. Если вы замените * в своем SELECT * только столбцами, упомянутыми выше (например, только user_id), вы сможете получить сканирование только индекса, которое будет очень быстрым.

ОБНОВЛЕНИЕ К сожалению, MySQL не поддерживает предложение WITH для общих табличных выражений, таких как PostgreSQL и некоторые другие базы данных. Но вы все равно можете выделить общее выражение следующим образом:

SELECT *
FROM questions q
JOIN Answers             a  ON q.user_id = a.user_id
JOIN bestAnswerByPoll    p  ON a.user_id = p.user_id
JOIN answerThumbRank     t  ON p.user_id = t.user_id
JOIN notes               n  ON t.user_id = n.user_id
JOIN interestingQuestion i  ON n.user_id = i.user_id,
(SELECT curdate() - interval 1 year AS year_ago) x
WHERE q.date > x.year_ago
  AND a.date > x.year_ago
  AND p.date > x.year_ago
  AND t.date > x.year_ago
  AND n.date > x.year_ago
  AND i.date > x.year_ago
person mvp    schedule 27.04.2013

В MySQL вы можете использовать функцию greatest():

WHERE DATEDIFF(CURDATE(), greatest(q.date, a.date, p.date, t.date, n.date, i.date)) > 365

Это поможет улучшить читаемость. Это не повлияет на производительность.

person Gordon Linoff    schedule 27.04.2013
comment
Спасибо! именно то, что мне было нужно - person Shai Zarzewski; 27.04.2013