Мне нужно получить данные из трех разных таблиц. Я знаю основы JOINs, но когда дело доходит до более сложных запросов, таких как получение данных из трех или более таблиц с помощью JOIN, я немного запутался, и я просто начинаю играть с запросами, пишущими, что имеет смысл для меня, как и следующий:
SELECT movies.imdbID,
movies.title,
movies.year,
movie_ratings.votes,
movie_ratings.total_value,
movie_ratings_external.votes,
movie_ratings_external.total_value
FROM movies, movie_ratings_external
LEFT JOIN movie_ratings ON movie_ratings.imdbID = movie_ratings_external.imdbID
WHERE movies.imdbID = movie_ratings_external.imdbID
ORDER BY movie_ratings.votes DESC, movie_ratings_external.votes DESC
LIMIT 30
Этот запрос работает. Я получаю выбранные поля из правильных таблиц и упорядочиваю правильный путь, но я думаю, что я смешиваю вещи (например, обычные запросы к двум таблицам и JOINING между двумя таблицами), и я уверен, что это лучший/более эффективный способ выполнения ту же самую пурпуру.
Доступен какой-нибудь DB geek?
Изменен ваш запрос чуть-чуть. Все остальное было довольно много.
Я не совсем уверен, что вы называете "регулярным запросом", но Joins - это почти основная часть обычного запроса.
В вашем старом запросе эта часть FROM movies, movie_ratings_external
была в основном CROSS JOIN
. Заменил его на JOIN
(я использовал a LEFT JOIN
, полагая, что вы всегда хотели вернуть все фильмы, но основное намерение состояло в том, что CROSS JOIN с фильтрацией в WHERE является намного более неэффективным, потому что вы манипулируете больше ROWS - особенно ненужные)
Подумайте об этом так. Каждый оператор Join в вашем SELECT возвращает набор строк, которые затем присоединяются к следующей таблице в JOIN. Идея должна состоять в том, чтобы последовательно пробовать строки фильтра с каждым объединением, насколько это возможно, чтобы вы не получали ненужные кортежи. То, где появляются утверждения ON.
Удалено
SELECT
movies.imdbID,
movies.title,
movies.year,
movie_ratings.votes,
movie_ratings.total_value,
movie_ratings_external.votes,
movie_ratings_external.total_value
FROM movies
LEFT OUTER JOIN movie_ratings_external
ON movies.imdbID = movie_ratings_external.imdbID
LEFT JOIN movie_ratings
ON movie_ratings.imdbID = movie_ratings_external.imdbID
ORDER BY movie_ratings.votes DESC, movie_ratings_external.votes DESC
LIMIT 30
Надеюсь, что это поможет!
Вы делаете 2 соединения. Однако вы смешиваете свои синтаксисы, что снижает читаемость.
Либо сделайте
SELECT movies.imdbID,
movies.title,
movies.year,
movie_ratings.votes,
movie_ratings.total_value,
movie_ratings_external.votes,
movie_ratings_external.total_value
FROM movies
LEFT JOIN movie_ratings_external ON movies.imdbID = movie_ratings_external.imdbID
LEFT JOIN movie_ratings ON movie_ratings.imdbID = movie_ratings_external.imdbID
ORDER BY movie_ratings.votes DESC, movie_ratings_external.votes DESC
LIMIT 30
или как это
SELECT movies.imdbID,
movies.title,
movies.year,
movie_ratings.votes,
movie_ratings.total_value,
movie_ratings_external.votes,
movie_ratings_external.total_value
FROM movies, movie_ratings_external, movie_ratings
WHERE movies.imdbID = movie_ratings_external.imdbID
AND movie_ratings.imdbID = movie_ratings_external.imdbID
ORDER BY movie_ratings.votes DESC, movie_ratings_external.votes DESC
LIMIT 30
Я также не уверен, почему вы остались. Если рейтинг может не существовать для определенного фильма, который вы хотите присоединиться к таблице фильмов.
Если это ваше намерение, ваш запрос должен выглядеть так.
SELECT movies.imdbID,
movies.title,
movies.year,
movie_ratings.votes,
movie_ratings.total_value,
movie_ratings_external.votes,
movie_ratings_external.total_value
FROM movies
LEFT OUTER JOIN movie_ratings_external ON movies.imdbID = movie_ratings_external.imdbID
LEFT OUTER JOIN movie_ratings ON movies.imdbID = movie_ratings.imdbID
ORDER BY movie_ratings.votes DESC, movie_ratings_external.votes DESC
LIMIT 30
В запросе ничего плохого. Но я предпочитаю что-то вроде следующего - ради удобочитаемости:
SELECT Movie.imdbID
, Movie.title
, Movie.year
, Rating.votes
, Rating.total_value
, ExternalRating.votes
, ExternalRating.total_value
FROM movies Movie
LEFT JOIN
movie_ratings_external ExternalRating
ON Movie.imdbID = ExternalRating.imdbID
LEFT JOIN movie_ratings Rating
ON Rating.imdbID = ExternalRating.imdbID
ORDER BY
Rating.votes DESC
, ExternalRating.votes DESC
Первый синтаксис, который вы используете
FROM tableA, tableB
WHERE tableA.abc = tableB.def
является еще одним синтаксисом для регулярного внутреннего соединения и, действительно, единственным синтаксисом, который вы можете использовать на некоторых СУБД, таких как Informix - эти два должны быть полностью эквивалентными. Я думаю, что сбивать с толку и сопоставлять синтаксисы, поэтому я бы выбрал один и придерживался его. Настоящим тестом было бы проверить план запросов mysql до и после переключения, но я был бы очень удивлен, если бы он вообще менял.
Эффективность: пока у вас есть индексы во всех правильных столбцах, т.е. столбец imdbID во всех трех таблицах, я не вижу ничего, что вы можете сделать, чтобы улучшить это. Я не думаю, что вам нужен индекс в столбцах, которые вы заказываете, но это может стоить проверить, если вы ищете улучшения.