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

Laravel多表Join查询结合Datatables加载慢优化咨询

财务数据查询与Datatables加载优化方案

针对你遇到的大数据量下查询慢、Datatables加载卡顿问题,从数据库查询、Laravel代码、前端配置三个层面给出具体优化方案:

一、数据库查询优化

1. 替换关联子查询为预聚合查询

原查询中eqivalent_sum使用关联子查询,每条financial_entries记录都会触发一次SUM计算,数据量上升后开销极大。改为提前聚合交易数据再关联,大幅减少计算次数:

// 预聚合credit类型的交易总和,仅执行一次聚合
$transactionSum = DB::table('finance_transaction')
    ->select('entry_id', DB::raw('ROUND(SUM(equivalent), 2) as eqivalent_sum'))
    ->where('type', 'credit')
    ->groupBy('entry_id');

// 主查询关联预聚合结果
$financial_entries = FinanceEntryMod::select([
    'ts.eqivalent_sum',
    'financial_entries.id',
    'financial_entries.created_by',
    'financial_entries.branch_id',
    'financial_entries.order_id',
    'financial_entries.number',
    DB::raw('IFNULL(branches.name, IFNULL(v2_branches.name, "main_branch")) AS branch_name'),
    'financial_entries.v2_order_id',
    'financial_entries.v2_document_id',
    'financial_entries.date',
    'financial_entries.is_generated',
    'financial_entries.note',
    'financial_entries.created_at',
    'financial_entries.updated_at',
    DB::raw('DATE_FORMAT(financial_entries.date, "%Y-%m-%d") AS new_date'),
    DB::raw('DATE_FORMAT(financial_entries.created_at, "%Y-%m-%d") AS new_created_at')
])
->leftJoinSub($transactionSum, 'ts', fn($join) => $join->on('ts.entry_id', '=', 'financial_entries.id'))
->leftJoin('branches', 'branches.id', '=', 'financial_entries.branch_id')
->leftJoin('finance_transaction', 'financial_entries.id', '=', 'finance_transaction.entry_id')
->leftJoin('finance_accounts', 'finance_accounts.id', '=', 'finance_transaction.account_id')
->leftJoin('v2_branches', 'v2_branches.id', '=', 'finance_accounts.v2_branch_id')
->where('financial_entries.is_deleted', '=', '0')
->groupBy('financial_entries.id');

注:原查询Joinfinance_transaction后再分组会导致数据先膨胀再压缩,预聚合方案避免了这个问题

2. 添加核心索引

给查询涉及的关联、过滤字段添加索引,直接提升数据库查询效率:

-- 交易表:按entry_id+type聚合的组合索引
CREATE INDEX idx_finance_trans_entry_type ON finance_transaction(entry_id, type);
-- 主表:过滤删除状态的索引
CREATE INDEX idx_financial_entries_is_deleted ON financial_entries(is_deleted);
-- 账户表:关联v2分支的索引
CREATE INDEX idx_finance_accounts_v2_branch ON finance_accounts(v2_branch_id);

确保各表主键(id)索引存在,这是关联查询的基础

3. 精简计算与字段

  • 把DATE_FORMAT日期格式化逻辑移到前端处理,减少数据库计算压力
  • 检查select中的字段,只保留Datatables实际需要的列,去掉冗余字段

二、Laravel代码层面优化

1. 适配Datatables服务器端参数

你已开启serverSide: true,但后端必须处理前端传递的分页、排序、搜索参数,否则会返回全量数据。推荐使用yajra/laravel-datatables扩展快速适配:

// 安装扩展后,直接返回处理后的结果
return DataTables::of($financial_entries)->make(true);

如果手动处理,需获取start/length/order/search参数,在查询中添加:

$start = request()->input('start', 0);
$length = request()->input('length', 30);
$orderColumn = request()->input('order.0.column', 'id');
$orderDir = request()->input('order.0.dir', 'asc');
$search = request()->input('search.value', '');

$financial_entries->skip($start)->take($length)
    ->orderBy($orderColumn, $orderDir)
    ->when($search, fn($q) => $q->where('financial_entries.number', 'like', "%{$search}%"));

2. 缓存非实时数据

如果财务数据更新频率低,用Redis缓存高频查询结果:

$cacheKey = 'financial_entries_' . md5(request()->query());
$financial_entries = Cache::remember($cacheKey, 300, function() {
    // 这里放你的查询代码
});

缓存时间根据业务需求调整,示例为5分钟

三、前端Datatables优化

1. 精简配置

{
    "pageLength": 20, // 减少单页加载数据量
    "serverSide": true,
    "processing": true,
    "deferRender": true, // 延迟渲染未显示的行
    "columns": [
        { "data": "id", "orderable": true, "searchable": true },
        { "data": "branch_name", "orderable": false, "searchable": false },
        // 其他列:给不需要排序/搜索的列关闭对应功能
    ]
}

2. 优化前端渲染

  • 用Datatables自带的render函数处理日期、金额格式化,避免全局循环处理数据
  • 关闭不必要的插件功能(如导出、打印),减少前端资源开销

内容的提问来源于stack exchange,提问作者OMAR R A SHAIKHOMAR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:21:27