Laravel带计数和位置的块

问题描述 投票:2回答:1

我想要一个包含选定用户组的列表,在这里我可以看到他们从特定日期开始有多少次点击。 Clicks是一个有几百万行的表,对我来说,最好的块点是约25万到50万的块值。 (此SQL查询花了2.4秒)

SELECT c.user_id, u.name, count(*) as aantal 
from clicks c
    join users u on c.user_id = u.id
where c.updated_at > '2020/02/09 20:00' and c.user_id not in (1, 3, 16, 18, 19, 20)
GROUP BY user_id;

对于每个用户的所有点击,此查询是否有效:

$users= User::has('clicks')
->withCount('clicks')
->orderBy('clicks_count', 'desc')
->get()
->whereNotIn('id', [1, 3, 16, 18, 19, 20])
->transform(function ($item) {
    // Remove all fields that you don't use inside the view
    unset($item->created_at, $item->updated_at, $item->admin, $item->email_verified_at);
    return $item;
});

为了获得总点击数,我发现了这一点:

$count = 0;
Click::chunk(500000, function($clicks) use (&$count)
{
    $count = $count + count($clicks);
});

我尝试了一些查询,但到目前为止没有任何效果。

我在想类似的东西:

$users = User::whereNotIn('id', [1, 3, 16, 18, 19, 20])->get();

foreach ($users as $user) {
    // Here find all CLicks for this user with later then a date with a Chunk
}

但是您将为每个用户浏览所有(很少的2-4)百万行,还有其他方法吗?

mysql laravel eloquent
1个回答
0
投票

[在我看来,当您处理大量数据时,您似乎采取了许多相互矛盾的方法,让sql尽您所能。以下查询将为您提供所需的所有数据。

Users::join('clicks', 'clicks.user_id', '=', 'u.id')->where('clicks.updated_at', '>', '2020/02/09 20:00')->whereNotIn('users.id', [1, 3, 16, 18, 19, 20]);

当您像这样连接数据时,sql将使行与每个用户重复的点击次数相同,因此我们必须使用分组依据将数据压缩回去。

...->groupBy('users.id');

使用总计来获得点击次数。

...->select('users.id', DB::raw('count(clicks.id) as clicks'));

这只会填充users.id和一个名为clicks的字段,其中包含点击次数。您应该避免对块执行任何操作。如果设置了外键,则此查询应该执行良好。

完整的查询应与此类似。由于分组依据,您不能选择其他字段,但是利用聚合函数max或min可以避免这种情况。

Users::join('clicks', 'clicks.user_id', '=', 'u.id')
    ->where('clicks.updated_at', '>', '2020/02/09 20:00')
    ->whereNotIn('users.id', [1, 3, 16, 18, 19, 20])
    ->groupBy('users.id')
    ->select('users.id', DB::raw('count(clicks.id) as clicks'))
    ->get();

推荐问答