1

我有一个有 10000 个用户的表,并且与work_hours表有关系。

这是我的用户模型以及我如何获得工作时间的总和。

protected $appends = ['sum_work_hours'];

public function work_hours()
{
    return $this->hasMany(WorkHour::class);
}

public function getSumWorkHoursAttribute()
{
    return $this->work_hours->sum('hours_total');
}

我进行了查询以显示所有用户及其工作时间总和,如下所示:

public function getHoursDatatable()
{
    $users = User::with('work_hours')->get();

    return Datatables::of($users)->make();
}

这个查询大约需要7-8 秒才能显示非常慢的表。

我知道这是因为汇总了work_hours每个用户的表中的总工作时间,如果考虑到数据量,我想了解如何优化此查询?

更新:

    $users = User::with('work_hours')->select(['users.name', 'users.email']);

    return Datatables::of($users)
        ->add_column('sum_work_hours', function(User $user) {
            return $user->work_hours->sum('hours_total');
        })
        ->make();

这给了我一个错误:

DataTables 警告:table id=users-table - Ajax 错误。有关此错误的更多信息,请参阅http://datatables.net/tn/7

更新 2

这有效:

public function getHoursDatatable()
{
    $users = User::with('work_hours');

    return Datatables::of($users)
        ->addColumn('sum_work_hours', function(User $user) {
            return $user->work_hours->sum('hours_total');
        })
        ->make();
}

但也需要大约7-8 秒才能加载...

4

1 回答 1

1

在某些时候,您的数据会变得太大而无法一次查询所有内容。

基本上你有2个选择:

1. 由于您已经有 10K 用户(而且这个数字可能还会增长?)我建议切换到异步(serverSide: true选项)。您正在使用数据表,因此显然您不需要一页中的所有 10K 用户,也不需要所有用户用于单个报告。

数据表确实允许服务器端处理,并且允许分页,同时保留过滤和排序的选项,就像您现在可能正在做的那样。

yajra 包将继续做它现在正在做的事情,你必须改变的是你没有将所有用户分配给视图并像那样构建它,你需要一个空表并让前端填充它. 只需创建一个 api 端点,您可以将数据表指向其中,以便从中获取分页列表。

因此@foreach ($users as $user),不要在您的视图中使用,不要在显示表格的控制器操作中获取它,让 api 端点处理它。

例子:

<table id="example" class="display" cellspacing="0" width="100%">
    <thead>
        <tr>
            <th>First name</th>
            <th>Last name</th>
            <th>Total Hours</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <th>First name</th>
            <th>Last name</th>
            <th>Total Hours</th>
        </tr>
    </tfoot>
</table>

你需要这样做(在这里或你正在使用的某个库中)

$(document).ready(function() {
    $('#example').DataTable( {
        "processing": true,
        "serverSide": true,
        "ajax": "../server_side/scripts/server_processing.php"
    } );
} );

您还需要:

//code.jquery.com/jquery-1.12.4.js https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js

如果您尚未将其包含在您的项目中,那么您的信息并不清楚。

有关更多信息,请参阅:数据表服务器端处理

2. 将总小时数存储在其他地方。完成对 Workhour 模型的更改后,您可以简单地更新每个用户的小时数。这样您就不需要在每次请求单个或列表(或所有)用户时都进行求和。

我的建议是至少做 #1 和 #2 之后将是一个很好的优化。

于 2017-09-03T20:58:55.590 回答