You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用query函数解决Laravel DataTable性能缓慢问题?

Laravel DataTable 性能优化方案

问题根源

你用Audit::select()和Audit::query()->select()本质完全一致,都是生成相同的查询构造器,所以不会带来任何性能提升。性能慢的核心原因大概率是索引缺失、查询数据量过大或者DataTable未启用服务端分页。

具体优化步骤

1. 强制添加必要索引

这是最直接有效的优化手段,先检查数据库索引情况:

  • 确保audits.user_id字段有索引(关联查询的核心关联键)
  • 给audits.created_at、audits.event这类DataTable常用的筛选/排序字段加索引
  • users.id默认是主键(已有索引,无需重复添加)

执行以下SQL添加索引:

-- 给audits.user_id添加单独索引
CREATE INDEX idx_audits_user_id ON audits(user_id);
-- 给常用筛选字段添加复合索引(如果经常按时间+事件组合筛选)
CREATE INDEX idx_audits_created_event ON audits(created_at, event);

2. 精简查询字段

如果DataTable不需要显示old_values和new_values(这两个通常是大体积JSON字段),直接从select中移除,能大幅减少数据传输和内存占用:

$audits = \OwenIt\Auditing\Models\Audit::select(
    'audits.id',
    'audits.user_type',
    'audits.user_id',
    'audits.event',
    'audits.auditable_id',
    'audits.auditable_type',
    'audits.created_at',
    'users.login'
)->join('users', 'users.id', '=', 'audits.user_id');

注意:原join语句缺少=符号,虽然Laravel会自动补全,但建议显式写出,避免语法歧义。

3. 启用DataTable服务端处理

这是Laravel DataTable性能优化的核心,不要把全量数据查出来交给前端处理,而是让DataTable通过AJAX请求分页加载数据(以Yajra DataTables为例):

  • 创建DataTable服务类:
namespace App\DataTables;

use OwenIt\Auditing\Models\Audit;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Services\DataTable;

class AuditDataTable extends DataTable
{
    public function query(Audit $model)
    {
        return $model->newQuery()
            ->select(
                'audits.id',
                'audits.user_type',
                'audits.user_id',
                'audits.event',
                'audits.auditable_id',
                'audits.auditable_type',
                'audits.created_at',
                'users.login'
            )
            ->join('users', 'users.id', '=', 'audits.user_id');
    }

    protected function getColumns()
    {
        return [
            Column::make('id'),
            Column::make('login')->title('操作人'),
            Column::make('event')->title('操作类型'),
            Column::make('created_at')->title('操作时间'),
            // 其他需要展示的列...
        ];
    }

    // 可添加筛选按钮、排序规则等配置...
}
  • 控制器中调用服务类:
public function index(AuditDataTable $dataTable)
{
    return $dataTable->render('audits.index');
}

这样DataTable会自动处理分页、筛选、排序逻辑,只查询当前页需要的10/20条数据,彻底避免全表扫描。

4. 关联查询优化

如果用户表数据量极大,可以通过子查询减少关联数据范围,比如只关联活跃用户:

$activeUsers = \App\Models\User::where('status', 1)->select('id', 'login');

$audits = \OwenIt\Auditing\Models\Audit::select(
    'audits.id',
    'audits.user_type',
    'audits.user_id',
    'audits.event',
    'audits.auditable_id',
    'audits.auditable_type',
    'audits.created_at',
    'users.login'
)->joinSub($activeUsers, 'users', function ($join) {
    $join->on('users.id', '=', 'audits.user_id');
});

验证优化效果

优化后可以通过以下方式验证查询效率:

DB::enableQueryLog();
$audits->get();
dd(DB::getQueryLog());

查看生成的SQL是否使用了索引,避免出现全表扫描的情况。

内容的提问来源于stack exchange,提问作者Rodrigo Franco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 01:15:32