#php #mysql #sql #laravel
Вопрос:
У меня есть следующие таблицы
Публикации - идентификатор - имя Категории - идентификатор - имя category_post - post_id - идентификатор категории
Post.php
public function Category()
{
return $this->belongsToMany(Category::class);
}
Category.php
public function posts()
{
return $this->belongsToMany(Post::class);
}
Сообщение может содержать множество категорий.
Я хочу запросить все сообщения, относящиеся к категориям любого данного сообщения, в наименьшем количестве запросов к базе данных.
Например, если сообщение относится к трем категориям, я хочу получить все сообщения, относящиеся к этим трем категориям. Я мог бы достичь этого за 4 запроса к БД, как показано ниже.
$post = Post::find(1);
$categoryIds = $post->category()->pluck('id');
$postIds = DB::table('category_post')
->whereIn('category_id', $categoryIds)
->pluck('post_id')
->unique();
$relatedPosts = DB::table('posts')
->whereIn('id', $postIds)
->get();
Мы будем очень признательны за любую помощь в сокращении запросов к БД или рефакторинге кода способом laravel.
Спасибо
Комментарии:
1. Просто в качестве записки. Если вы делаете это, потому что считаете, что меньшее количество запросов означает лучшую производительность, то это неверно. Гораздо важнее, что делают запросы, а не сколько их, за заметным исключением стоимости передачи данных, которая будет применяться только в том случае, если база данных находится за пределами локальной сети сервера виртуальной локальной сети.
2. @apokryfos да, я это понимаю. В данном конкретном случае, как вы думаете, не будет ли какой-либо разницы в производительности между моим кодом и вашим, скажем, для 25 категорий и 5000 сообщений?
3. В данном конкретном случае я думаю, что главным преимуществом является экономия памяти на веб-сервере, поскольку вы не загружаете частичные данные для подготовки следующего запроса, в дополнение к тому, что вам не нужно выполнять первый запрос для получения модели, если вы уже знаете идентификатор. Я думаю, что время, необходимое для обоих методов, будет масштабироваться одинаково, поскольку основным трудоемким процессом является «присоединение» к таблице сообщений через категории, что является неизбежной операцией
4. @apokryfos Спасибо за ваши подробные разъяснения
Ответ №1:
Ваш приведенный пример может быть написан так:
$postWithRelatedPosts = Post::whereHas('category.post', function ($q) {
$q->where('id', 1);
})->get();
Это один запрос, но в нем есть 2 подзапроса. Это порождает что-то вроде:
select *
from `posts`
where exists (
select *
from `categories` inner join `category_post` on `categories`.`id` = `category_post`.`category_id`
where `posts`.`id` = `category_post`.`post_id` and exists (
select *
from `posts` inner join `category_post` on `posts`.`id` = `category_post`.`post_id`
where `categories`.`id` = `category_post`.`category_id` and `id` = ?
)
)
Комментарии:
1. Спасибо @apokryfos за ответ. Это сработало именно так, как я хотел.