如何优化大查询?
How to optimize a big query?
我有一个有 10000 个用户的 table 并且与 work_hours
table.
有关系
这是我的用户模型以及我如何获得工作时间总和。
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 秒 来显示 table,这非常慢。
我知道这是因为对每个用户 work_hours
table 的总工作时间进行了总结,我想了解如何优化此查询,如果考虑到数量,这甚至是可能的数据?
更新:
$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 warning: table id=users-table - Ajax error. For more
information about this error, please see 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 秒...
在某些时候,您的数据会变得太大而无法一次查询所有内容。
基本上你有两个选择:
1。
由于您已经有 10K 用户(而且这个数字可能还会增长?)我建议切换到异步(serverSide: true
选项)。您正在使用数据tables,所以显然您不需要在一个页面中显示所有 10K 个用户,也不需要所有这些用户用于单个报告。
Datatables 确实允许服务器端处理,它确实允许分页,同时保留过滤和排序选项,就像您现在可能正在做的那样。
yajra 包将继续做它现在正在做的事情,你必须改变的是你没有将所有用户分配给视图并像那样构建它,你需要一个空 table 并让前端填充它。只需创建一个 api 端点,您可以将数据 table 指向该端点,以便从中获取分页列表。
因此,不要在您的视图中使用 @foreach ($users as $user)
,不要在显示 table 的控制器操作中获取它,让 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
如果您尚未将其包含在您的项目中,那么您的信息中并不清楚。
有关详细信息,请参阅:Datatables Server-side processing
2。
将总小时数存储在其他地方。当对 Workhour 模型的更改完成后,您可以简单地更新每个用户的总小时数。这样您就不需要在每次请求单个或列表(或所有)用户时都进行求和。
我的建议是至少做#1,然后#2 会是一个很好的优化。
我有一个有 10000 个用户的 table 并且与 work_hours
table.
这是我的用户模型以及我如何获得工作时间总和。
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 秒 来显示 table,这非常慢。
我知道这是因为对每个用户 work_hours
table 的总工作时间进行了总结,我想了解如何优化此查询,如果考虑到数量,这甚至是可能的数据?
更新:
$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 warning: table id=users-table - Ajax error. For more information about this error, please see 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 秒...
在某些时候,您的数据会变得太大而无法一次查询所有内容。
基本上你有两个选择:
1。
由于您已经有 10K 用户(而且这个数字可能还会增长?)我建议切换到异步(serverSide: true
选项)。您正在使用数据tables,所以显然您不需要在一个页面中显示所有 10K 个用户,也不需要所有这些用户用于单个报告。
Datatables 确实允许服务器端处理,它确实允许分页,同时保留过滤和排序选项,就像您现在可能正在做的那样。
yajra 包将继续做它现在正在做的事情,你必须改变的是你没有将所有用户分配给视图并像那样构建它,你需要一个空 table 并让前端填充它。只需创建一个 api 端点,您可以将数据 table 指向该端点,以便从中获取分页列表。
因此,不要在您的视图中使用 @foreach ($users as $user)
,不要在显示 table 的控制器操作中获取它,让 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
如果您尚未将其包含在您的项目中,那么您的信息中并不清楚。
有关详细信息,请参阅:Datatables Server-side processing
2。 将总小时数存储在其他地方。当对 Workhour 模型的更改完成后,您可以简单地更新每个用户的总小时数。这样您就不需要在每次请求单个或列表(或所有)用户时都进行求和。
我的建议是至少做#1,然后#2 会是一个很好的优化。