Я переписал этот запрос несколько раз (это понедельник) с попыткой найти наиболее эффективный способ получения требуемых данных, но я не уверен, что я даже приближаясь к нему правильно в данный момент.MYSQL Optimizing JOINED UNION SELECT query
Чтобы подвести итог данной проблеме;
Пользователи имеют два набора тегов (key_terms
, project_terms
), есть таблица связи между каждым из них между users
и tags
таблицами.
Я хотел бы вытащить всех пользователей, указавших теги в любой таблице. В идеале он также будет включать в себя «наиболее релевантный» тег для этого пользователя, но на этот раз отложил это.
пользователи
| id | name |
| 1 | dayjo |
| 2 | stackoverflow |
теги
| id | tag |
| 1 | tag1 |
| 2 | tag2 |
user_key_term
| user_id | tag_id |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
project_key_term
| user_id | tag_id |
| 1 | 3 |
| 2 | 3 |
Я хочу, чтобы иметь возможность запрашивать, это именованные теги, т.е. если я ищу «tag1», оба пользователя должны быть возвращены, однако если я ищу «tag2», то должен быть возвращен только пользователь 1.
Мои решения
Я попытался с помощью выбора пользователей, а также присоединение тегов дважды (по одному для каждой таблицы ссылок), это, казалось, работало нормально, но не был уверен, что это лучший способ, и не мог выяснить, как получить наиболее релевантный тег.
SELECT t1.tag, t2.tag as most_relevant_tag, users.* FROM users
LEFT JOIN user_key_term ON user_key_term.user_id = users.id
LEFT JOIN tags t1 ON user_key_term.tag_id = t1.id
LEFT JOIN project_key_term ON project_key_term.user_id = users.id
LEFT JOIN tags t2 ON project_key_term.tag_id = t2.id
WHERE t1.tag IN ('tag1','tag2') OR t2.tag IN ('tag1','tag2')
GROUP BY users.id;
Моя следующая попытка была выбрана UNION, но этот человек чувствует себя грязным;
SELECT users.* FROM
`users`
INNER JOIN (
SELECT project_key_term.user_id, tags.id, tags.tag FROM project_key_term
JOIN tags ON tags.id = project_key_term.tag_id AND tags.tag IN ('tag1')
UNION ALL
SELECT user_key_term.user_id,tags.id, tags.tag FROM user_key_term
JOIN tags ON tags.id = user_key_term.tag_id AND tags.tag IN ('tag1')
) tags ON tags.user_id = users.id
WHERE tags.tag IN ('tag1')
GROUP BY users.id;
Но
Я попытался запустить EXPLAIN на обоих запросов, чтобы увидеть, что лучше всего, но ничего особенно полезного не показывают мне. Тем более, что на данный момент в таблицах не так много данных, потенциально могут быть сотни/тысячи тегов.
Любая помощь по «правильной» или наилучшей практике для выполнения такого запроса была бы замечательной!
Вы можете объединить две таблицы key_term и добавить столбец типа дифференцироваться. Если тег может отображаться только в одной из этих таблиц, вы можете добавить столбец типа вместо тега и иметь только одну таблицу key_term. – Arth
Да, это, безусловно, может быть вариантом!В таблице «project» фактически есть другое поле «project_id». Я решил сохранить ORM красивым и аккуратным, они должны быть раздельными, поскольку они будут управляться (несколько) отдельно. Это сделает его намного быстрее, и у меня будет только один JOIN. Я, конечно же, подумаю об этом, вы знаете, почему бы не иметь ВСЕ таблицы ссылок в одной таблице с полем «тип» и общие поля «table1_id», «table2_id»? ;) – Joel
А, ок. В заявлении UNION вы можете фактически удалить 'WHERE tags.tag IN ('tag1')' из внешнего SELECT, поскольку он является избыточным. – Arth