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

如何提升PHP生成CSV文件的速度?现有实现运行过慢求优化方案

CSV生成慢的优化方案

当前代码的核心性能瓶颈是N+1次SQL查询:外层查询一次订单列表后,每遍历一个订单都要单独执行2次SQL查询客户信息和订单商品明细,若查询到1000个订单,就会产生2001次数据库请求,大量时间浪费在PHP和数据库的通信开销上。可按以下优先级优化:

1. 合并SQL查询,消灭N+1问题

用JOIN语句把三张表的查询合并为1次,一次性获取所有需要的字段,大幅减少数据库交互次数。
参考合并后的SQL:

SELECT 
    o.ordr_timedate, o.ordr_id, o.ordr_cust_id, o.ordr_b_company, o.ordr_shipping_selected,
    c.cust_gl_code,
    oc.orcn_prod_code, oc.orcn_prod_part_num, oc.orcn_prod_name, oc.orcn_prod_type, oc.orcn_option_0, oc.orcn_price, oc.orcn_qty, oc.orcn_total
FROM shop_orders o
LEFT JOIN shop_customers c ON o.ordr_cust_id = c.cust_id
LEFT JOIN shop_orders_content oc ON o.ordr_id = oc.orcn_ordr_id
WHERE 
    o.ordr_ship_id = {$sid}
    AND o.ordr_timedate BETWEEN {$strdate} AND {$enddate}
ORDER BY o.ordr_timedate DESC

调整后只需要遍历一次SQL查询结果,直接组装CSV行即可,无需循环内再查数据库。

2. 添加数据库索引,加速查询

给涉及的查询字段加索引,避免全表扫描:

  • 给shop_orders表添加联合索引:INDEX idx_ship_date (ordr_ship_id, ordr_timedate),覆盖WHERE筛选和ORDER BY排序逻辑,同时可以把需要查询的订单字段加到索引里做成覆盖索引,避免回表查询
  • 给shop_orders_content表添加索引:INDEX idx_ordr_id (orcn_ordr_id),加速订单和商品明细的关联查询
  • shop_customers表的cust_id如果不是主键/没有索引,也要单独添加

3. PHP层优化,减少IO开销

  • 如果生成CSV是用于用户下载,不要写入本地磁盘,直接输出到php://output流,省掉磁盘写入开销,示例代码:
// 直接输出到浏览器,不需要生成本地文件
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=orders-by-supplier.csv');
$file = fopen('php://output', 'w');
  • 读取查询结果时使用mysqli_fetch_assoc代替mysqli_fetch_array,避免生成无用的数字索引数组,减少内存占用
  • 不要把所有查询结果加载到内存后再写CSV,采用边查边写的流式处理,降低内存峰值

4. 超大数据量分批处理

如果符合条件的记录超过10万条,可以采用分批查询的方式:每次用LIMIT查询1000~5000条记录,处理完后再查下一批,避免单次查询占用过多数据库内存和PHP内存,同时保证处理速度。

内容的提问来源于stack exchange,提问作者Noob Coder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 04:06:04