报表处理优化案例全攻略(二)

案例:如何高效汇总月报数据

一、背景

在数据仓库和业务分析场景中,通常需要将每日增量数据(天数据)汇总生成月度报表(月报),但传统处理方式存在低效问题,如重复计算相同维度(如时间、地区、产品、渠道等),导致大量冗余SQL查询,SQL可能多次全表扫描,造成I/O和计算资源浪费;此外,部分方案依赖临时表存储中间结果但缺乏持久化优化,导致重复加工,而任务调度若未合理编排,月报任务可能重复触发部分计算,影响时效性。这些问题导致月报生成慢、资源浪费,亟需优化存储和计算逻辑,减少重复查询,提升效率。

二、案例讲解

1、月报维度条件清晰明确

1.1、为确保数据汇总效率,需预先明确时间、区域、产品等维度组合,并在程序中记录已计算的维度条件。通过缓存机制或状态标记,每次执行前校验是否已处理,避免重复聚合。例如,若某日某地区的销售数据已汇总,后续任务直接跳过或引用结果,减少冗余计算和SQL查询,提升月报生成性能。

2.2、为避免逐日重复查询,应一次性按维度组合(如时间、区域、产品等)拉取整月数据统一计算。例如,通过SQL的`WHERE`条件限定月份范围直接聚合,而非每天单独执行。这样减少数据库连接和扫描次数,提升查询效率,同时确保数据一致性,避免多次计算相同维度导致的结果偏差。

2、代码处理过程

2.1、明确定义维度,程序校验判重,避免重复查询计算,提升汇总效率。

/**

* 处理数据

* @param $params 条件集

* @param $start 月开始时间

* @param $end 月结束时间

* @return void

*/

public function handleHumanEfficiencyMonthData($params, $start,$end)

{

$storeDayData = [];

MarketReportCommon::dataGetIdProces(

$params,

function ($dataList) use ($params,$start,$end,&$storeDayData) {

$insertAllData = [];

foreach($dataList as $dataValue){

$day = date('Y-m-01',$dataValue['date']);

$uniqueKey = $dataValue['project_user_id'].'_'.$day;

if(!in_array($uniqueKey,$storeDayData) && !isset($insertAllData[$uniqueKey])){

$bindConfig = $this->configMonthData[$dataValue['project_user_id']]?? [];

$insert = $this->getHumanEfficiencyMonthTotalData($dataValue,$bindConfig,$start,$end);

$storeDayData[] = $uniqueKey;

if(empty($insert)){

continue;

}

$insertAllData[$uniqueKey] = $insert;

}

}

if(!empty($insertAllData)) {

$insertAllData = array_values($insertAllData);

$insertAlls = array_chunk($insertAllData,10);

foreach($insertAlls as $insertAll){

HumanEfficiencyUserReport::insertAll($insertAll);

}

unset($insertAllData,$insertAlls);

}

}

);

}

2.2、按月维度统一查询全量数据,避免逐日扫描,提升聚合效率。

/**

* 获取一月的汇总值

* @param $dataValue 参数集

* @param $bindConfig 配置条件

* @param $start 月开始时间

* @param $end 月结束时间

* @return array

* @throws \think\Exception

*/

public function getHumanEfficiencyMonthTotalData($dataValue,$bindConfig,$start,$end){

$where = [];

$where[] = ['project_user_id','=',$dataValue['project_user_id']];

$timeResult = MarketReportCommon::makeStartEndTime($start, $end);

$where[] = ['date', 'between', [$timeResult[0], $timeResult[1]]];

$sumFields = [

'order_num', 'sales_revenue', 'promotion_expenses', 'logistics_cost', 'purchasing_cost', 'exchange_loss', 'collection_fee', 'platform_fee', 'refund_loss', 'fixed_cost', 'return_cost', 'group_salary',

'actual_profit','fixed_cost_reality','refund_loss_reality','logistics_cost_reality','exchange_loss_reality','monthly_rental_fee','app_fee','transaction_fees','tariff_fee'

];

$fields = [];

$defaultFields = ['department_id','store_group_id','project_user_id','( sum(sales_revenue) - ( SUM(promotion_expenses)+ sum(logistics_cost) + sum(purchasing_cost) + sum(exchange_loss) + sum(collection_fee) + sum(platform_fee) +sum(refund_loss) + sum(fixed_cost) + sum(return_cost) + sum(group_salary)+sum(tariff_fee) ) ) as gop'];

$sumFields = FuncCommon::setSumField($sumFields);

$fields = array_merge($defaultFields,$sumFields);

$totalData = DailyReports::where($where)->field($fields)->findOrEmpty()->toArray();

if(empty($totalData)){

return [];

}

return self::assembleHumanEfficiencyMonthTotalInsert($dataValue,$totalData,$bindConfig,$start);

}

三、结果

减少了SQL查询,减少对数据库的压力;CPU使用率降低,保障响应速度。