PHP, оптимизация запросов и задачи, паттерны решения проблемы. Как сделать функциональность быстрее и лучше
Я программирую блог и столкнулся с проблемой. Автоблог.
Суть состоит в том, что на страницу нужно вывести post, информацию пользователя который написал данный пост, количество комментариев + комментарии, количество подписчиков и подписок пользователя, количество лайков поста.
Я использую yii2 ( для REST API )
Тоесть приблизительно для вывода одной страницы мне нужно сделать много запросов в БД, а именно:
Вот так я получаю данные по посту, информацию по авто и так далее
$query = $this->getPostSelect();
$query->addSelect([
'user_cars.id as userCarId',
'user_cars.makeId',
'user_cars.modelId',
'user_cars.generationId',
'makes.name as makeName',
'models.defaultName as modelDefaultName',
'models.name as modelName',
'generations.defaultName as generationDefaultName',
'generations.name as generationName',
'user_cars.carUsername',
'cars_posts.costAmount',
'cars_posts.costCurrency',
])
->innerJoin(UserCars::tableName(), 'cars_posts.carId = user_cars.id')
->innerJoin(Makes::tableName(), 'user_cars.makeId = makes.id')
->innerJoin(Models::tableName(), 'user_cars.modelId = models.id')
->innerJoin(Generations::tableName(), 'user_cars.generationId = generations.id');
$post = $query->where(['cars_posts.id' => $postId])
->orderBy(['cars_posts.id' => SORT_DESC])
->asArray()
->one();
метод getPostSelect
return $this::find()
->select([
'cars_posts.id',
'cars_posts.title',
'cars_posts.categoryId',
'cars_posts.content',
'cars_posts.userId',
'cars_posts.createdAt',
'cars_posts.mileage',
'cars_posts.coverUrl',
'user.username',
'user.country',
'user.avatar',
'user.city',
'categories.id as categoryId',
'categories.name'
])
->innerJoin(User::tableName(), 'user.id = cars_posts.userId')
->innerJoin(Categories::tableName(), 'categories.id = cars_posts.categoryId');
Далее мне нужно получить количество комментариев по посту:
public function getCountComments($postId){
return self::find()->where(['postId' => $postId])->count();
}
далее получить комментарии: Для пагинации использую lastId, вместо offset (работает на много быстрее)
public function getPostComments($lastId, $postId)
{
return self::find()->select(['id', 'comment', 'date'])
->where(['postId' => $postId])
->andWhere(['<', 'id', $lastId])
->limit(10)
->all();
}
Далее получить количество лайков поста
public function getCountLikes()
{
return self::find()->where(['postId' => $postId])->count();
}
Далее получить количество подписок и подписчиков для пользователя который написал данные пост. И вот здесь я задался вопрос, а не слишком ли много запросов в базу данных для получения информации для одного поста?
Как это оптимизировать?
Мои мысли таковы:
Слишком тяжелый и большой запрос на получение информации поста. Получать имя модели, марки, генерации и категории можно по другому, а именно переделать все это на отдельные запросы SELECT и их закешировать, данные будут браться с кеша и пропадет большая связка и запрос будет работать быстрее.
Получать количество комментариев. Сохранять комментарии в БД , а также информацию обновлять в кеше (Redis? FileCache?). Тоесть пользователь написал комментарий:
ДОбавить комментарий в базу данных
В кеше будет храниться массив индификаторов комментариев и при добавлении комментария добавлять его на начало масива в кеше (аналогично и с удалением комментария, удаляем в БД и удаляем в кеше). Затем взять массив с кеша и подсчитать количество (а это означает что для подсчета количества комментариев мы не будем трогать БД)
Аналогично и с лайками, храним информацию в БД(кто поставил лайк на какой пост) и обновляем инфу в кеше
Аналогично с количество подписок и подписчиков
Так я вижу как возможно оптимизировать. И тогда для получения информации мы делаем 1-ин запрос на получение поста, все остальное берем с кеша.
Правильный ли такой подход? Как правильно или лучше было бы оптимизировать данную логику и решить проблему? Правильная ли логика для средне нагружаемоего блога? Уж очень не хочеться на столько сильно трогать БД. Если решение логично и правильно, какой кеш лучше использовать? Очень хорошо Redis, и очень удобен в работе, также стандарный yii2 FileCache.
P.S Таблицы проиндексированы.