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

MySQL导出CSV邮件附件脚本添加text字段后挂起问题咨询

问题分析与解决方案

是的,note_text这个TEXT类型字段就是导致脚本挂起的核心原因,结合6万条数据的场景,具体问题出在这几点:

核心问题

  1. 内存过载:TEXT字段可存储最大64KB(或更大,取决于MySQL配置)的内容,6万条数据一次性全部读取到PHP数组$data中,会瞬间占用大量内存,很容易超出PHP默认的内存限制,导致脚本卡死或无响应。
  2. 处理效率低下:将所有数据存入数组后,还要在内存中生成完整CSV字符串,再进行base64编码(编码后数据体积会膨胀约33%),这个过程会进一步加剧内存消耗,让进程长时间处于资源占用状态,最终挂起。

解决方案

1. 改用逐行处理,避免一次性加载所有数据

不要把所有数据都读到内存数组里,而是边查询数据库边写入CSV文件,大幅降低内存占用。

2. 生成物理CSV文件,而非内存字符串

直接将数据写入临时CSV文件,再读取文件内容处理邮件附件,避免内存中存储超大字符串。

3. 优化邮件发送逻辑(可选)

用专业邮件库(如PHPMailer)替代原生mail()函数,处理大附件更稳定,也无需手动拼接复杂的多部分邮件结构。

修改后的完整代码

<?php
$mysqli = new mysqli("localhost", "*****", "*****", "****");

if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

// 创建临时CSV文件,用于存储导出数据
$csvFile = tempnam(sys_get_temp_dir(), 'notes_backup');
$fp = fopen($csvFile, 'w');
if (!$fp) {
    die("无法创建临时CSV文件");
}

// 写入CSV表头
fputcsv($fp, array('ID', 'job_ID', 'note_date', 'note_author', 'note_text', 'flagged', 'FAO', 'time', 'category'));

// 使用预处理语句逐行读取数据库数据,避免一次性加载所有记录
$query = "SELECT ID, job_ID, note_date, note_author, note_text, flagged, FAO, time, category FROM funeral_job_notes";
if ($stmt = $mysqli->prepare($query)) {
    $stmt->execute();
    // 绑定结果到变量
    $stmt->bind_result($id, $jobId, $noteDate, $noteAuthor, $noteText, $flagged, $fao, $time, $category);
    
    // 逐行读取并写入CSV
    while ($stmt->fetch()) {
        fputcsv($fp, array($id, $jobId, $noteDate, $noteAuthor, $noteText, $flagged, $fao, $time, $category));
    }
    
    $stmt->close();
}
fclose($fp);
$mysqli->close();

function send_csv_mail($csvFilePath, $body, $to = 'me@me.com', $from = 'server@me.com', $subject = 'notes backup') {
    $multipartSep = '-----'.md5(time()).'-----';

    // 读取CSV文件内容并进行base64编码
    $csvContent = file_get_contents($csvFilePath);
    $attachment = chunk_split(base64_encode($csvContent));

    $headers = array(
        "From: $from",
        "Reply-To: $from",
        "Content-Type: multipart/mixed; boundary=\"$multipartSep\""
    );

    // 拼接邮件内容
    $bodyContent = "--$multipartSep\r\n"
                . "Content-Type: text/plain; charset=ISO-8859-1; format=flowed\r\n"
                . "Content-Transfer-Encoding: 7bit\r\n"
                . "\r\n"
                . "$body\r\n"
                . "--$multipartSep\r\n"
                . "Content-Type: text/csv; name=\"AFILE.csv\"\r\n"
                . "Content-Transfer-Encoding: base64\r\n"
                . "Content-Disposition: attachment; filename=\"AFILE.csv\"\r\n"
                . "\r\n"
                . "$attachment\r\n"
                . "--$multipartSep--";

    $sendResult = mail($to, $subject, $bodyContent, implode("\r\n", $headers));
    
    // 发送完成后删除临时文件
    unlink($csvFilePath);
    
    return $sendResult;
}

// 执行邮件发送
echo "emaling now <br>";
$resp = send_csv_mail($csvFile, "job notes backup");

if( $resp ){
    echo "Mail sent <br>" ;
} else {
    echo "Mail not sent <br>";
}
echo "all done <br>";
?>

额外优化建议

  • 临时调整PHP配置:如果仍遇到超时或内存不足,在脚本开头添加:
    ini_set('memory_limit', '256M'); // 根据实际情况调整,比如512M
    set_time_limit(300); // 设置最长执行时间,单位秒
    
  • 改用PHPMailer:原生mail()函数处理大附件稳定性较差,PHPMailer支持SMTP协议,还能直接添加文件附件,无需手动处理base64编码,大幅降低出错概率。
  • 分批次导出:若单份CSV体积过大,可分多次查询(比如每次查1万条),生成多个附件分开发送,或压缩CSV后再发送。

内容的提问来源于stack exchange,提问作者Mark hardy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:21:03