Laravel Eloquent最大限度地提高效率,但保持优雅的结构

时间:2015-02-06 19:08:01

标签: php sql laravel

我在我的应用程序的敏感部分工作,我需要确保最小化查询的数量。我可以通过多个连接轻松完成此操作。问题是:有没有办法用美容做到这一点?

Elequent relationships是一个很好的起点,但大多数时候需要多次查询。

article中使用的急切加载方法看起来更好但仍需要至少2个查询并使用whereIn语句而不是连接。

Article渴望加载的例子:

$users = User::with('posts')->get();

foreach($users as $user)
{
  echo $user->posts->title;
}

使用Eager Loading,Laravel实际上将运行以下

select * from users
select * from posts where user_id in (1, 2, 3, 4, 5, ...) 

我目前的解决方案是以非意图的方式使用laravel范围。

    public static function scopeUser($query) // join users table and user_ranks
    {
        return $query->join('users', 'users.id', '=', 'posts.user_id')
                     ->join('user_ranks', 'users.rank_id', '=', 'user_ranks.id');
    }
    public static function scopeGroup($query,$group_id) // join feeds,group_feeds (pivot) and groups tables
    {
        return $query->join('feeds', 'feeds.id', '=', 'posts.feed_id')
                     ->join('group_feed', 'feeds.id', '=', 'group_feed.feed_id')
                     ->join('groups', 'groups.id', '=', 'group_feed.group_id')
                     ->where("groups.id","=",$group_id);
    }

生成的查询如下所示:

$posts = Post::take($limit)
                ->skip($offset)
                ->user()                   // scropeUser
                ->group($widget->group_id) // scropeGroup
                ->whereRaw('user_ranks.view_limit > users.widget_load_total')
                ->groupBy('users.id')
                ->orderBy('posts.widget_loads', 'ASC')
                ->select(
                             'posts.id AS p_id',
                             'posts.title AS p_title',
                             'posts.slug AS p_slug',
                             'posts.link AS p_link',
                             'posts.created_on AS p_create_on',
                             'posts.description AS p_description',
                             'posts.content AS p_content',
                             'users.id AS u_id',
                             'users.last_name AS u_last_name',
                             'users.first_name AS u_first_name',
                             'users.image AS u_image',
                             'users.slug AS u_slug',
                             'users.rank_id AS u_rank',
                             'user_ranks.name AS u_rank_name',
                             'user_ranks.view_limit AS u_view_limit'
                         )
                ->get();

由于列名冲突,我需要一个巨大的select语句。这工作并产生一个单一的查询,但它远非性感!

有没有更好的方法来处理大型连接查询?

1 个答案:

答案 0 :(得分:1)

您可以尝试在范围内实际添加带别名的选择。

注意:这是完全未经测试的

public static function scopeUser($query) // join users table and user_ranks
{
    foreach(Schema::getColumnListing('users') as $column){
        $query->addSelect('users.'.$related_column.' AS u_'.$column);
    }
    $query->addSelect('user_ranks.name AS u_rank_name')
          ->addSelect('user_ranks.view_limit AS u_view_limit');

    $query->join('users', 'users.id', '=', 'posts.user_id')
          ->join('user_ranks', 'users.rank_id', '=', 'user_ranks.id');

    return $query;
}

也没有必要使用p_前缀为帖子列添加别名...但如果您真的想要,请添加另一个范围,并使用addSelect()