Laravel 框架关联 has in 实现

v3.0.0 2024-05-27 13:43 UTC

README

英文 | 中文

LARAVEL HASIN

hasin 是一个基于 where in 语法查询 Laravel ORM 关系的 composer 包,它可以在某些业务场景中替代基于 where exists 语法的 has,以获得更高的性能。

安装

介绍

Laravel ORM 的关系非常强大,基于关系的查询 has 也为我们提供了许多灵活的调用方法。然而,在某些情况下,has 使用的是 where exists 语法。

例如

// User hasMany Post
User::has('posts')->get();

select * from users where exists (select * from posts where users.id = posts.user_id)

'exists' 是一个对外部表的循环,每次都查询内部表(子查询)。因为用于查询内部表的索引(内部表效率高,因此可以用作大表),以及需要遍历外部表的比例,是不可避免的(尽量使用小表),所以对于大内部表使用 exists 可以提高效率。

然而,当 User 有大量数据时,会出现性能问题,所以 where in 语法将大大提高性能。

select * from users where users.id in (select posts.user_id from posts)

'in' 是将外部表和内部表进行哈希连接,首先查询内部表,然后匹配内部表的结果与外部表,并使用外部表的索引(外部表效率高,可以用于大表)。大多数内部表都需要查询,这是不可避免的。因此,对于大的外部表使用 'in' 可以提高效率。

因此,在代码中使用 has(hasMorph)hasIn(hasMorphIn) 应根据 数据量大小 来决定

/**
 * SQL:
 * 
 * select * from `users` 
 * where exists 
 *   ( 
 *      select * from `posts` 
 *      where `users`.`id` = `posts`.`user_id` 
 *   ) 
 * limit 10 offset 0
 */
$users = User::has('posts')->paginate(10);

/**
 * SQL:
 * 
 * select * from `users` 
 * where `users`.`id` in  
 *   ( 
 *      select `posts`.`user_id` from `posts` 
 *   ) 
 * limit 10 offset 0
 */
$users = User::hasIn('posts')->paginate(10);

使用示例

hasIn(hasMorphIn) 支持 Laravel ORM 中的所有 关系。调用方式和内部实现与框架中的 has(hasMorph) 完全一致。

hasIn

// hasIn
User::hasIn('posts')->get();

// orHasIn
User::where('age', '>', 18)->orHasIn('posts')->get();

// doesntHaveIn
User::doesntHaveIn('posts')->get();

// orDoesntHaveIn
User::where('age', '>', 18)->orDoesntHaveIn('posts')->get();

whereHasIn

// whereHasIn
User::whereHasIn('posts', function ($query) {
    $query->where('votes', '>', 10);
})->get();

// orWhereHasIn
User::where('age', '>', 18)->orWhereHasIn('posts', function ($query) {
    $query->where('votes', '>', 10);
})->get();

// whereDoesntHaveIn
User::whereDoesntHaveIn('posts', function ($query) {
    $query->where('votes', '>', 10);
})->get();

// orWhereDoesntHaveIn
User::where('age', '>', 18)->orWhereDoesntHaveIn('posts', function ($query) {
    $query->where('votes', '>', 10);
})->get();

hasMorphIn

Image::hasMorphIn('imageable', [Post::class, Comment::class])->get();

嵌套关系

User::hasIn('posts.comments')->get();

测试

composer test

提示:在测试之前,您需要在 phpunit.xml.dist 中配置您的数据库连接。

许可证

MIT