Как получить 5 максимальных значений из каждой категории в MySQL?

Как я могу улучшить запрос, чтобы вывести по каждой номинации 5 фильмов с максимальным количеством баллов, используя данные из таблицы голосов (votes)? Мой текущий запрос выполняется около 30 секунд для таблицы с 25 000 строками и затем завершается ошибкой.
  • 28 января 2024 г. 1:48
Ответы на вопрос 2
Чтобы получить 5 максимальных значений из каждой категории в MySQL, можно использовать оконные функции (если ваша версия MySQL 8.0 или выше) или эмулировать их поведение в более ранних версиях. 

Сперва давайте рассмотрим вариант с использованием оконных функций:

```sql
SELECT *
FROM (
    SELECT 
        v.*,
        RANK() OVER (PARTITION BY category_id ORDER BY score DESC) as rank
    FROM votes v
) as ranked
WHERE rank <= 5;
```

В этом запросе:

- `RANK() OVER (PARTITION BY category_id ORDER BY score DESC)` - оконная функция, которая присваивает ранги внутри каждой категории (`PARTITION BY category_id`), упорядочивая их по убыванию баллов (`ORDER BY score DESC`).
- Затем выбираются только те записи, где ранг меньше или равен 5 (`WHERE rank <= 5`).

Если оконные функции не поддерживаются вашей версией MySQL, можно использовать следующий метод:

```sql
SELECT v1.*
FROM votes v1
WHERE (
    SELECT COUNT(DISTINCT v2.score)
    FROM votes v2
    WHERE v2.score > v1.score AND v1.category_id = v2.category_id
) < 5
ORDER BY v1.category_id, v1.score DESC;
```

В этом запросе подзапрос в `WHERE` клозе подсчитывает, сколько есть уникальных баллов больше текущего, и ограничивает эту выборку пятью наиболее высокими баллами для каждой категории.

Для улучшения производительности запросов, убедитесь, что:

1. Индексированы столбцы `category_id` и `score`, чтобы ускорить сортировку и операции фильтрации.
2. Если используются дополнительные условия (`WHERE`), подумайте о создании составных индексов, которые соответствуют вашему запросу.

Кроме того, проверьте настройки сервера MySQL, в частности, доступное количество памяти и параметры конфигурации, такие как `sort_buffer_size` и `join_buffer_size`, которые могут повлиять на производительность выполнения запросов.

Если ваша таблица содержит большое количество строк и проблема заключается в чрезмерном использовании ресурсов, отконфигурируйте запросы и/или используйте шардинг или разбиение на партиции в таблице. Это поможет уменьшить объем данных, обрабатываемых каждым запросом, и, как следствие, улучшить производительность.
См. оконную функцию row_number для MySQL 8+ версия, либо MariaDB. Но учтите, что MySQL 5 не поддерживает оконки.
Похожие вопросы