案例:如何高效汇总月报数据
一、背景
在数据仓库和业务分析场景中,通常需要将每日增量数据(天数据)汇总生成月度报表(月报),但传统处理方式存在低效问题,如重复计算相同维度(如时间、地区、产品、渠道等),导致大量冗余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使用率降低,保障响应速度。