В моем приложении PHP у меня есть таблица статей mysql, которая имеет следующие столбцы:
article_id articletext category_id score
Каждая статья имеет оценку, которая рассчитывается на основе того, насколько она популярна и относится к определенной категории (доступно около 10 категорий)
Мой вопрос: как я могу выполнить запрос, который возвращает наивысшие удаленные статьи, чередуя их по категориям, чтобы, если возможно, статьи одинаковой категории возвращались последовательно. Например, если наивысшая баллская оценка имеет счет: 100 возвращаемый набор будет примерно таким:
article_id articletext category_id score ----------------------------------------------------- 142 <.....> 5 100 153 <.....> 3 97 119 <.....> 5 99 169 <.....> 2 93 121 <.....> 7 89 197 <.....> 2 92 . . .
Первое (наивное) решение, которое приходит в голову, выполняет 10 выборок (по 1 для каждой категории), упорядочивая их по убыванию, а затем, на уровне PHP, чередуя каждый возвращаемый набор данных, одновременно получая один результат и объединяя их вместе в новом массиве.
Есть ли более эффективный способ достичь этого? Если возможно, на уровне MySQL
Пойдите, получите верхнюю 20. Если они не удовлетворяют требованиям, сделайте дополнительный запрос, чтобы получить недостающие части. Вы должны иметь возможность найти некоторый баланс между количеством запросов и количеством строк, которые возвращаются.
Я получил 100 лучших, которые могли удовлетворить требования в 90% случаев и были бы дешевле и быстрее, чем 10 отдельных запросов.
Если бы это был SQL Server, я мог бы помочь больше …
На самом деле, у меня есть другая идея. Запускайте процесс каждые 5 минут, который вычисляет список и кэширует его в таблице. Сделать DML против связанных таблиц недействительными кэш-память, поэтому он не используется до повторного заполнения (возможно, статья была удалена). Если кеш недействителен, вы можете вернуться к его вычислению на лету … И может использовать это, чтобы повторно кэшировать кеш.
Возможно, можно будет стратегически обновить кеш-список, а не пересчитать его. Но это может быть реальной проблемой.
Это должно помочь как с частотой запросов, так и с уменьшением нагрузки на вашу базу данных. Это не имеет большого значения, если ваш список статей на 5 минут устарел. Черт, даже 1 минута может работать.
Просто для обучения цели. Я провел тест с тремя категориями. Я не знаю, как этот запрос мог работать на большом наборе записей.
select * from ( (select @r:=@r+1 as rownum,article_id,articletext,category_id,score from articles,(select @r:=0) as r where category_id = 1 order by score desc limit 100000000) union all (select @r1:=@r1+1,article_id,articletext,category_id,score from articles,(select @r1:=0) as r where category_id = 2 order by score desc limit 100000000) union all (select @r2:=@r2+1,article_id,articletext,category_id,score from articles,(select @r2:=0) as r where category_id = 3 order by score desc limit 100000000) ) as t order by rownum,score desc
Ваше наивное решение – именно то, что я буду делать.