首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP addAll 批量插入最大資料量限制:max_allowed_packet 配置詳解

     編輯:PHP 相關知識

ThinkPHP addAll() 批量寫入效能與 MySQL 封包大小限制

addAll() 將多筆資料合併為單一 INSERT ... VALUES (...), (...), ... 語句,大幅優於循環 add()。但受限於 MySQL max_allowed_packet 參數,超大批次會導致「MySQL server has gone away」錯誤。

基本用法

$User = M("User");
$dataList = [
    ['name' => 'thinkphp', 'email' => 'thinkphp@gmail.com'],
    ['name' => 'onethink', 'email' => 'onethink@gmail.com'],
];
$User->addAll($dataList);
// 生成 SQL:INSERT INTO `user` (`name`,`email`) VALUES ('thinkphp','...'),('onethink','...')

核心限制:max_allowed_packet

  • MySQL 預設 max_allowed_packet = 4MB(5.6+ 預設 4MB,8.0+ 預設 64MB)
  • 單條 SQL 語句長度不得超過此值
  • 批次筆數 × 平均行長度 > 此值 → 錯誤

解決方案

1. 調整 MySQL 配置

[mysqld]
max_allowed_packet = 100M

重啟 MySQL 生效:systemctl restart mysqld

2. 應用層分批處理(推薦)

function batchInsert($model, $dataList, $batchSize = 500) {
    $chunks = array_chunk($dataList, $batchSize);
    foreach ($chunks as $chunk) {
        $model->addAll($chunk);
    }
}

// 使用
batchInsert($User, $largeDataList, 200); // 每 200 筆一批

3. 動態計算安全批次大小

function safeBatchInsert($model, $dataList, $maxPacket = 16 * 1024 * 1024) {
    // 估算單行平均長度
    $sample = array_slice($dataList, 0, 10);
    $avgLen = strlen($model->getLastSql()) / max(1, count($sample));
    $safeBatch = max(1, floor($maxPacket * 0.8 / $avgLen)); // 留 20% 緩衝

    foreach (array_chunk($dataList, $safeBatch) as $chunk) {
        $model->addAll($chunk);
    }
}

效能對比

方式1萬筆耗時SQL 數量記憶體
循環 add()~15 秒10,000低
addAll() 一次性~0.8 秒1高(可能 OOM)
addAll() 分批(500)~1.2 秒20適中

最佳實踐建議

  1. 永遠分批,避免單一巨大 SQL
  2. 批次大小 100~1000 視行寬度調整
  3. 事務包裹批次:$model->startTrans(); ... $model->commit();
  4. 監控 max_allowed_packet 與 innodb_log_file_size
  5. 超大量匯入考慮 LOAD DATA INFILE 或 mysqldump

總結

addAll() 是批量寫入利器,但必須尊重 MySQL 協議限制。分批策略兼顧效能與穩定,是生產環境的標準做法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved