#php #mysql #sql
Вопрос:
Чтобы ускорить мой запрос, я paginate
в соответствии с первичным ключом id
, который установлен в качестве начального значения, т. е. posts.id > $start
Вот как я получаю регулярные сообщения, т. е. id
они извлекаются последовательно при следующем запросе запроса
// start value
$start = $_GET['start'];
if ($start <= 0) {
// set as first request
$offSet = "AND posts.id > $start";
}
else if ($start > 0) {
// set as subsequent request
$offSet = "AND posts.id < $start";
}
// fetch posts
$posts = $db->query("SELECT posts.id, posts.likes,
posts.dislikes, posts.comments
FROM posts, users
WHERE posts.user_id=users.id
$offSet
ORDER BY posts.id DESC LIMIT 0, 15");
Вот как я выбираю наиболее понравившиеся посты
// fetch posts
$posts = $db->query("SELECT posts.id, posts.likes,
posts.dislikes, posts.comments
FROM posts, users
WHERE posts.user_id=users.id
$offSet
AND posts.likes != 0
ORDER BY posts.likes DESC LIMIT 0, 15");
Проблема в том , что если я ORDER BY likes DESC
, id
то не буду последовательным, и, следовательно, если я запрошу больше сообщений, результаты повторят первый набор результатов.
Может ли кто-нибудь помочь мне написать запрос, который будет получать сообщения ORDER BY posts.likes DESC
и при этом позволит мне разбивать запрос на страницы на основе id
, чтобы последующие запросы постепенно не замедлялись (из-за того, что mysql просматривает все предыдущие строки)
Это реализация, любезно предоставленная @RickJames
$start = $leftoff_likes = 0;
// fetch most liked posts
$posts = $db->query("
SELECT posts.id, posts.body, posts.user_id, posts.tag, posts.date, posts.comments, posts.likes, posts.dislikes, users.name, users.image
FROM posts, users
WHERE posts.likes <= $leftoff_likes
AND ( posts.likes < $leftoff_likes OR posts.id < $start )
AND posts.user_id=users.id
ORDER BY posts.likes DESC, posts.id DESC
LIMIT 0, 15");
echo json_encode($posts);
Комментарии:
1. Используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ вместо запятой
2. Что вы имеете в виду
3. Вместо
FROM a,b WHERE a.x=b.x
того , чтобы делатьFROM a JOIN b ON a.x=b.x
. Они имеют один и тот же эффект; последний является «современным» синтаксисом.4. да, спасибо @RickJames, это действительно хорошо работает!
Ответ №1:
Эффективное соединение:
Вам нужно 2 столбца ORDER BY
, чтобы лучше оформить заказ. И это усложняет WHERE
предложение, особенно когда несколько пунктов имеют одинаковое количество лайков.
Начиная с наиболее понравившихся:
SELECT ...
WHERE likes <= $leftoff_likes
AND ( likes < $leftoff_likes OR id < $leftoff_id )
ORDER BY likes DESC, id DESC
LIMIT 16
Начиная с наименее понравившегося:
SELECT ...
WHERE likes >= $leftoff_likes
AND ( likes > $leftoff_likes OR id > $leftoff_id )
ORDER BY likes ASC, id ASC
LIMIT 16
Отобразите первые 15 результатов на текущей странице и установите (для следующего раза) $leftoff_likes и $leftoff_id из 16-го элемента. Передайте их по URL [Next]
-адресу за кнопками [Prev]
и.
OFFSET
никогда не используется.
Есть, если это практически, INDEX(likes, id)
(Этот наконечник был спрятан в http://mysql.rjweb.org/doc.php/deletebig#iterating_through_a_compound_key )
Примечания к сборнику:
«Вспоминать, на чем вы остановились» лучше, чем использовать LIMIT
с OFFSET
. См.: http://mysql.rjweb.org/doc.php/pagination
Это приводит к многочисленным изменениям. Я рекомендую написать два полных запроса вместо исправления с $offset
помощью .
Комментарии:
1. спасибо, не могли бы вы объяснить это немного подробнее, пожалуйста, используя мой код выше.
2. Ах, я кое-что пропустил
$start
-этого недостаточно, вам тоже нужно помнить$likes
. Замените $Род и $вид на $нравится и $начало.3. для меня $лайки не являются переменной величиной, я должен заменить их постами. нравится? Мне немного трудно сопоставить их.
4. @MaxNjoroge — Когда вы заканчиваете с одной страницей, у вас есть два числа, обозначающие, где страница «остановилась» —
likes
иid
«последней» строки, выбранной для страницы. Они поступают из переменныхSELECT
into PHP, затем в URL-адрес для кнопки [Далее] или [Предыдущая] и обратно в PHP, чтобы использовать их как $likes и $id для следующей страницыSELECT
. Смотрите мой блог о разбиении на страницы. (Он рекомендует выбрать 16 строк и запомнитьlikes
иid
из 16-го; это изменяет » > » на «> > = » и т. Д.)5. Спасибо @RickJames и @Luuk, оказывается, код @RickJames работает просто отлично. @Luuk, Это не сработало, потому что мой запрос был вложен, в
$db->query()
который с интервалом и новой строкой не работал. Но в остальном код @RickJames работает просто отлично. Спасибо @Luuk за вашу скрипку, которая заставила меня это увидеть!