Оптимизируйте SQL-запрос, используя `COUNT`

У меня есть SQL-запрос (я использую MariaDB/MySQL), который работает нормально. Но мне интересно, могу ли я упростить/оптимизировать его. Трудность, с которой я сталкиваюсь, связана с COUNT с INNER JOIN. Мне действительно нужен подзапрос IN или вы думаете, что есть способ его устранить?

SELECT a.* 
FROM aaa a 
INNER JOIN bbb b ON a.field1 = b.field1 
WHERE a.yyy = 'yyy' AND b.zzz = 'zzz' 
AND a.field1 IN (
    SELECT field1 
    FROM bbb 
    WHERE xxx = 'x' 
    GROUP BY field1 
    HAVING COUNT(field1) <= 5
)

Благодарю вас!

Пожалуйста, опубликуйте описание таблицы, объясните план

Ergest Basha 10.05.2022 20:53
Вам нужно показать нам определения таблицы и индекса, а также количество строк для каждой из таблиц. Возможно, ваши таблицы плохо определены. Возможно, индексы созданы неправильно. Возможно, у вас нет индекса в том столбце, который, как вы думали, у вас есть. Не видя определений таблиц и индексов, мы не можем сказать. Нам нужно количество строк, потому что это может повлиять на планирование запросов. Если вы знаете, как сделать EXPLAIN или получить план выполнения, также укажите результаты в вопросе. Если у вас нет индексов, посетите использовать-индекс-luke.com.
Andy Lester 10.05.2022 22:55

Кроме того, нам нужно увидеть фактический запрос, а не его перефразированную версию.

Andy Lester 10.05.2022 22:55
Освоение архитектуры микросервисов с 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
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
3
46
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш запрос может быть максимально хорошим, но вы также можете попробовать присоединиться к подзапросу вместо использования IN.

SELECT DISTINCT a.*
FROM aaa AS a
INNER JOIN bbb b ON a.field1 = b.field1 
INNER JOIN (
    SELECT field1 
    FROM bbb 
    WHERE xxx = 'x' 
    GROUP BY field1 
    HAVING COUNT(*) <= 5
) AS bc ON a.field1 = bc.field1
WHERE a.yyy = 'yyy' AND b.zzz = 'zzz' 

Мне очень жаль, мой друг, я забыл добавить AND b.zzz = 'zzz' к моему запросу! Мне очень нужно bbb! Я отредактировал свой вопрос, хорошо?

Jonathan 10.05.2022 20:57
Ответ принят как подходящий

Мне нравится ответ Бармара, но из-за фильтрации b я предлагаю небольшое (?) изменение. (Я перестраиваю таблицы в первую очередь в соответствии с вероятным порядком оптимизатора.)

SELECT DISTINCT a.*
FROM  (
    SELECT field1 
    FROM bbb 
    WHERE xxx = 'x' 
    GROUP BY field1 
    HAVING COUNT(*) <= 5
) AS bc
INNER JOIN bbb AS b ON b.field1 = bc.field1 
INNER JOIN aaa AS a ON a.field1 = bc.field1
WHERE b.zzz = 'zzz' 
  AND a.yyy = 'yyy'

Плюс эти индексы:

    bbb:  INDEX(xxx, field1)  -- this order
    b:    INDEX(field1, zzz)  -- either order
    a:    INDEX(field1, yyy)  -- either order

Первые два составных индекса будут «покрывающими».

Основное изменение по сравнению с ответом Бармара заключалось в том, чтобы оставить a.* напоследок.

Если вы хотите продолжить обсуждение этого вопроса, может быть полезно предоставить SHOW CREATE TABLE и EXPLAIN.

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