UNION ALL MYSQL очень медленный

У меня есть запрос в mysql с двумя вариантами выбора. Когда я запускаю эти запросы по отдельности, они выполняются быстро в течение 1 секунды. Но когда я объединяю их с объединением всех, веб-сайт зависает, и выполнение одного и того же запроса в объединении всех занимает не менее 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

Сколько строк возвращает каждый из подзапросов?

Barmar 21.12.2020 21:50

@Barmar около 2 миллионов каждый.

Naklov 21.12.2020 21:52

Сначала выполните ORDER BY и LIMIT 10 в каждом SELECT. Затем сделайте это на СОЮЗЕ ВСЕХ результатов тоже.

jarlh 21.12.2020 21:54

Ваша проблема заключается в предложении ORDER BY. UNION должен получить все записи, а затем отсортировать их.

Sourcerer 21.12.2020 21:58
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
4
399
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

UNION по умолчанию имеет значение UNION DISTINCT. Если вы хотите использовать UNION ALL, прямо скажите это (и вы должны это делать везде, где это возможно, поскольку UNION DISTINCT должен проделать большую работу, чтобы сделать их разными).

Другое дело, что порядок и ограничение применяются к запросу в целом. Возможно, вы захотите, чтобы каждый объединенный запрос также имел их. См. https://dev.mysql.com/doc/refman/8.0/en/union.html:

ORDER BY и LIMIT в союзах

Чтобы применить предложение 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

Я забыл добавить UNION ALL сюда, в stackoverflow. Я изменил это. Спасибо.

Naklov 21.12.2020 21:53

Этот запрос вернет всего 2 строки; 10 и 11.

jarlh 21.12.2020 22:29

Это вернет до 20 строк.

Barmar 21.12.2020 22:33

@Barmar, первый SELECT вернет до 10 строк, все значения 10. Второй SELECT вернет до 10 строк, все значения 11. UNION удалит дубликаты и вернет только один 10 и один 11 (если оба значения существуют.)

jarlh 21.12.2020 22:35

Это не соответствует исходному запросу, поскольку им нужны первые 10 строк из двух комбинированных запросов.

Barmar 21.12.2020 22:38

поскольку запрос из документации, похоже, смутил некоторых из вас, добавил один, настроенный на этот вопрос.

ysth 21.12.2020 22:43
Ответ принят как подходящий

Перед слиянием с помощью 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

вы можете просто использовать круглые скобки, а не подзапрос, чтобы упорядочить/ограничить отдельные запросы; посмотри мой ответ

ysth 21.12.2020 22:23

Но вам нужен внешний выбор, чтобы отфильтровать его до 10 лучших комбинированных запросов.

Barmar 21.12.2020 22:31

нет, не знаешь. вы можете заказать и ограничить отдельные запросы, а также заказать и ограничить союз в целом

ysth 21.12.2020 22:40

о, не знал, что ты можешь сделать это так, как ты показываешь.

Barmar 21.12.2020 22:43

Другие вопросы по теме