#mysql #sql #join #select #union-all
#mysql #sql #Присоединиться #выберите #объединение всех
Вопрос:
У меня есть запрос в mysql с 2 select from. Когда я запускаю эти запросы по отдельности, они выполняются быстро в течение 1 секунды. Но когда я объединяю их с union all, веб-сайт зависает, и для выполнения одного и того же запроса в union all требуется не менее 20 секунд.
Есть идеи, почему это происходит? Не могу понять.
Смотрите Запрос ниже:
SELECT p.user_id, p.description, p.post_id, p.created_at, ps.username AS size_name, ps.username AS user_name, ps.avatar AS avatar, pz.title AS title, pz.slug AS slug
FROM comments p
JOIN users ps ON ps.id = p.user_id
JOIN posts pz ON pz.id = p.post_id
UNION ALL
SELECT p2.user_id, p2.description, p2.post_id, p2.created_at, ps2.username AS size_name, ps2.username AS user_name, ps2.avatar AS avatar, pz2.title AS title, pz2.slug AS slug
FROM reply p2
JOIN users ps2 ON ps2.id = p2.user_id
JOIN posts pz2 ON pz2.id = p2.post_id
order by created_at DESC
LIMIT 10
Комментарии:
1. Сколько строк возвращает каждый из подзапросов?
2. @Barmar около 2 м каждый.
3. Сначала СДЕЛАЙТЕ ЗАКАЗ и ОГРАНИЧЬТЕ 10 в каждом ВЫБОРЕ. Затем сделайте это и для результата ОБЪЕДИНЕНИЯ ВСЕХ.
4. Ваша проблема заключается в предложении ORDER BY. ОБЪЕДИНЕНИЮ необходимо получить все записи, а затем отсортировать их.
Ответ №1:
Перед объединением с UNION
уменьшите размер таблиц, возвращаемых каждым подзапросом. Поскольку вам нужны только 10 лучших, вам нужны только 10 лучших из каждого подзапроса.
SELECT *
FROM (
(SELECT p.user_id, p.description, p.post_id, p.created_at, ps.username AS size_name, ps.username AS user_name, ps.avatar AS avatar, pz.title AS title, pz.slug AS slug
FROM comments p
JOIN users ps ON ps.id = p.user_id
JOIN posts pz ON pz.id = p.post_id
ORDER BY created_at DESC
LIMIT 10)
UNION ALL
(
SELECT p2.user_id, p2.description, p2.post_id, p2.created_at, ps2.username AS size_name, ps2.username AS user_name, ps2.avatar AS avatar, pz2.title AS title, pz2.slug AS slug
FROM reply p2
JOIN users ps2 ON ps2.id = p2.user_id
JOIN posts pz2 ON pz2.id = p2.post_id
ORDER BY created_at DESC
LIMIT 10)
) AS x
order by created_at DESC
LIMIT 10
Комментарии:
1. вы можете просто использовать круглые скобки, а не подзапрос, чтобы иметь порядок по / limit для отдельных запросов; см. Мой ответ
2. Но вам нужен внешний select, чтобы отфильтровать его до 10 лучших объединенных запросов.
3. нет, вы этого не делаете. вы можете упорядочивать и ограничивать отдельные запросы, а также упорядочивать и ограничивать объединение в целом
4. о, не знал, что вы можете сделать это так, как вы показываете.
Ответ №2:
ОБЪЕДИНЕНИЕ по умолчанию имеет значение UNION DISTINCT . Если вы хотите ОБЪЕДИНИТЬ ВСЕ, прямо скажите это (и вы должны, где это возможно, поскольку UNION DISTINCT должен проделать большую работу, чтобы сделать их разными).
Другое дело, что порядок и ограничение применяются к запросу в целом. Возможно, вы захотите, чтобы в каждом объединенном запросе они тоже были. Смотрите https://dev.mysql.com/doc/refman/8.0/en/union.html:
ПОРЯДОК и ОГРАНИЧЕНИЕ в объединениях
Чтобы применить предложение ORDER BY или LIMIT к отдельному SELECT, заключите SELECT в круглые скобки и поместите предложение в круглые скобки:
(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
Если в ваших быстрых отдельных версиях они были, это должно помочь. Итак, что-то вроде этого:
(SELECT p.user_id, p.description, p.post_id, p.created_at, ps.username AS size_name, ps.username AS user_name, ps.avatar AS avatar, pz.title AS title, pz.slug AS slug
FROM comments p
JOIN users ps ON ps.id = p.user_id
JOIN posts pz ON pz.id = p.post_id
order by created_at DESC
LIMIT 10)
UNION ALL
(SELECT p2.user_id, p2.description, p2.post_id, p2.created_at, ps2.username AS size_name, ps2.username AS user_name, ps2.avatar AS avatar, pz2.title AS title, pz2.slug AS slug
FROM reply p2
JOIN users ps2 ON ps2.id = p2.user_id
JOIN posts pz2 ON pz2.id = p2.post_id
order by created_at DESC
LIMIT 10)
order by created_at DESC
LIMIT 10
Комментарии:
1. Я забыл добавить ОБЪЕДИНЕНИЕ ALL здесь, в stackoverflow. Я изменил его. Спасибо.
2. Этот запрос вернет только 2 строки; 10 и 11.
3. Это вернет до 20 строк.
4. @Barmar, первый ВЫБОР вернет до 10 строк, все значения 10. Второй ВЫБОР вернет до 10 строк, все значения 11. ОБЪЕДИНЕНИЕ удалит дубликаты и вернет только одно 10 и одно 11 (если оба значения существуют.)
5. Это не соответствует исходному запросу, поскольку им нужны верхние 10 строк из двух объединенных запросов.