匯出百萬級資料

辰曦發表於2023-10-30

記錄一下(初步實現)

<?php
//讓程式一直執行  
set_time_limit(0);
//設定程式執行記憶體  
ini_set('memory_limit', '128M');
$fileName = '商品匯出資料';
header('Content-Encoding: UTF-8');
header("Content-type:application/vnd.ms-excel;charset=UTF-8");
header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
//開啟php標準輸出流 
$fp = fopen('php:output', 'a');
//新增BOM頭,以UTF8編碼匯出CSV檔案,如果檔案頭未新增BOM頭,開啟會出現亂碼。  
fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
//新增匯出標題
  fputcsv($fp, ['商品', '價格', '庫存']);  
//連結資料庫
$dsn = "mysql:host=127.0.0.1;port=3306;dbname=db_www;charset=utf8";
$pdo = new PDO($dsn, 'root', '');
$step = 100;
//迴圈次數 
$nums = 10000;
//每次匯出數量 
for ($i = 0; $i < $step; $i++) {
    $start = $i * 10000;
    $sql = "SELECT product_code,price,qty FROM `products` ORDER BY `id` LIMIT {$start},{$nums}";
    $productMysql = $pdo->query($sql);
    $result = $productMysql->fetchAll(PDO::FETCH_ASSOC);
    foreach ($result as $item) {
        fputcsv($fp, $item);
    }
    //每1萬條資料就重新整理緩衝區  
 ob_flush();
    flush();
}

根據大佬們的建議修整後為

<?php
//讓程式一直執行
set_time_limit(0);
//設定程式執行記憶體
ini_set('memory_limit', '128M');
$fileName = '商品匯出資料';
header('Content-Encoding: UTF-8');
header("Content-type:application/vnd.ms-excel;charset=UTF-8");
header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
//開啟php標準輸出流
$fp = fopen('php:output', 'a');
//新增BOM頭,以UTF8編碼匯出CSV檔案,如果檔案頭未新增BOM頭,開啟會出現亂碼。
fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
// 新增匯出標題
fputcsv($fp, ['商品', '價格', '庫存']);

// 連結資料庫
$dsn  = "mysql:host=127.0.0.1;port=3306;dbname=db_www;charset=utf8";
$pdo  = new PDO($dsn, 'root', '');

$nums   = 10000; // 每次查詢的數量
$lastId = 0; // 上一批資料的最後一個ID
do {
    $sql = "SELECT product_code, price, qty FROM `products` WHERE id > :lastId ORDER BY `id` LIMIT :nums";
    $stmt = $pdo->prepare($sql);
    $stmt->bindParam(':lastId', $lastId, PDO::PARAM_INT);
    $stmt->bindParam(':nums', $nums, PDO::PARAM_INT);
    $stmt->execute();
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($result as $item) {
        fputcsv($fp, $item);
    }
    $lastId = $result[count($result) - 1]['id'];
    ob_flush();
    flush();
} while (count($result) > 0);

fclose($fp);
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章