PHP调用CheckAQI函数渲染HighChart图表时加载速度过慢问题咨询
性能问题核心原因
单次CheckAQI执行会触发2次数据库查询,当前业务需要查询3个站点、过去14天的AQI数据,循环累计触发84次数据库查询,是加载慢的核心诱因。另外代码存在低级错误、查询无索引、冗余逻辑也进一步放大了性能损耗。
具体优化方案
1. 先修复现有代码明显错误
- 两个PHP函数的参数定义为
$connection,实际内部调用的连接变量是$con,参数不匹配 pollute_data函数的参数列表末尾缺右括号- Township系列的AQI计算结果变量是
$GraphTownshipAQI,判断是否为空用的是$GraphMobileAQI,变量名错误导致数据异常
2. 数据库层优化
- 给
test_uploads表加联合索引:ALTER TABLE test_uploads ADD INDEX idx_stat_date (station_id, dateandtime, O3),走覆盖索引查询日均数值无需回表,单次查询耗时可从几十毫秒降到1毫秒以内 - AQI分级规则是固定配置,无需每次计算都查库,提前一次性加载到内存即可
// 全局提前加载所有AQI分级规则,只查1次库 $aqi_rules = []; $sql = "SELECT * FROM aqiindex"; $res = mysqli_query($con, $sql); while($row = mysqli_fetch_assoc($res)) { $aqi_rules[] = $row; } // 改造pollute_data直接从内存匹配规则,完全省去库查询 function pollute_data($pollutant, $pollutant_value, $aqi_rules) { $pollutant_lower = strtolower($pollutant); $col1 = $pollutant_lower. '_lower'; $col2 = $pollutant_lower. '_upper'; foreach($aqi_rules as $rule) { if($pollutant_value >= $rule[$col1] && $pollutant_value <= $rule[$col2]) { return [$rule[$col1], $rule[$col2], $rule['aqi_lower'], $rule['aqi_upper']]; } } return [0,0,0,0]; }
3. 批量查询业务数据,替代循环单条查询
原来42次单站点单日期的查询,改成1次SQL拉取所有需要的原始数据:
// 计算查询的时间范围 $end_date = $date; $start_date = date("Y-m-d", strtotime("-14 day", strtotime($end_date))); // 一次性查询3个站点14天的日均O3数据 $sql = " SELECT station_id, DATE(dateandtime) as stat_date, SUM(O3)/COUNT(O3) as o3_polluant FROM test_uploads WHERE dateandtime >= '$start_date 00:00:00' AND dateandtime <= '$end_date 23:59:59' AND station_id IN (1,2,3) GROUP BY station_id, DATE(dateandtime) "; $res = mysqli_query($con, $sql); // 整理成 站点ID->日期->数值 的数组方便后续取值 $station_data = []; while($row = mysqli_fetch_assoc($res)) { $station_data[$row['station_id']][$row['stat_date']] = $row['o3_polluant']; }
4. 后端统一组装图表数据,前端直接渲染
避免在JS代码里嵌套多层PHP循环,后端提前组装成HighChart需要的JSON格式,既减少冗余逻辑也避免JS语法错误:
// 组装横轴日期和三个站点的序列数据 $categories = []; $series = [ ['name' => 'Township AQMS', 'data' => []], ['name' => 'Townhall AQMS', 'data' => []], ['name' => 'Mobile AQMS', 'data' => []], ]; $my_date = $date; for($i=1;$i<15;$i++) { $time = strtotime("-1 day",strtotime($my_date)); $my_date = date('Y-m-d', $time); $categories[] = date("d,m,Y", $time); // 循环三个站点计算AQI foreach([1,2,3] as $idx => $station_id) { $o3_val = $station_data[$station_id][$my_date] ?? 0; $aqidata = pollute_data('O3', $o3_val, $aqi_rules); // AQI计算逻辑和原代码一致 $pl_lower = $aqidata[0]; $pl_upper = $aqidata[1]; $aqi_lower = $aqidata[2]; $aqi_upper = $aqidata[3]; $Idiff = $aqi_upper - $aqi_lower; $Bpdiff = $pl_upper - $pl_lower; $aqi = $Bpdiff > 0 ? (($Idiff * ($o3_val - $pl_lower)) / $Bpdiff) + $aqi_lower : 0; $aqi = floor($aqi * 100) / 100; $series[$idx]['data'][] = is_nan($aqi) ? 0 : $aqi; } } // 转成JSON供前端直接使用 $categories_json = json_encode($categories); $series_json = json_encode($series);
前端代码简化为:
<script src="highchart/highcharts.src.js"></script> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function () { Highcharts.chart('container', { chart: { type: 'column' }, title: { text: 'AQI Historic Data' }, xAxis: { categories: <?php echo $categories_json; ?> }, yAxis: { title: { text: 'AQI Range' } }, series: <?php echo $series_json; ?> }); }); </script>
5. 后续扩展6种污染物的兼容方案
批量查询的SQL里新增其他污染物的均值计算字段,AQI计算时遍历6种污染物分别计算、取最大值作为当日AQI即可,无需修改核心逻辑结构。
6. 可选进阶优化
如果页面访问量较高,可以把计算好的14天AQI数据存入文件缓存或者Redis,缓存有效期设为1~24小时(根据数据更新频率调整),无需每次请求都重新计算,页面加载耗时可降到100毫秒以内。
内容的提问来源于stack exchange,提问作者Hafiz Muhammad Ejaz
相关产品推荐
相关产品推荐

