Yii2 通过 excel 文件长加载时间更新数据

Yii2 update data by excel file long load time

我正在使用 Yii2 创建一个工具来管理我的团队的工作量。所以每天我都需要使用 Excel 将大量数据(大于 5k)导入数据库,加载时间通常需要大约 20-30 分钟。有什么办法可以缩短加载时间吗?

请帮我解决这个问题。

这是我使用的代码:

public function actionImportExcel()
{
    $inputFile = 'uploads/importexcel/import.csv';
    try{
        $inputFileType = \PHPExcel_IOFactory::identify($inputFile);
        $objReader = \PHPExcel_IOFactory::createReader($inputFileType);
        $objPHPExcel = $objReader->load($inputFile);
    }catch(Exception $e)
    {
            die('Error');
    }

    $sheet = $objPHPExcel->getSheet(0);
    $highestRow = $sheet->getHighestRow();
    $highestColumn = $sheet->getHighestColumn();

    for( $row = 1; $row <= $highestRow; $row++)
    {
        $rowData = $sheet->rangeToArray('A'.$row.':'.$highestColumn.$row,NULL,TRUE,FALSE);

        if($row == 1)
        {
            continue;
        }
    $test = $rowData[0][0];

    $ext = Sku3d::find()->where(['sku' => $test])->exists();



    if($ext){
        $one = Sku3d::find()->where(['sku' => $test])->one();
        $one->status = $rowData[0][14];
        $one->round = $rowData[0][19];
        $one->source = $rowData[0][29];
        $one->modeler = $rowData[0][30];
        if($one->datesubmit == NULL || $one->datesubmit == ""){
        $one->save();   
        }else{
        $day = DateTime::createFromFormat('Y-m-d', $one->datesubmit);
        $one->monthsubmit=date("Y-m-t", strtotime($one->datesubmit));
        $one->save();
        }
        if($rowData[0][14] == "Approved"){
            $one->approvedate = $rowData[0][16];
            if($one->approvedate == NULL || $one->approvedate == ""){
            $one->save();   
            }else{
            $one->approvemonth=date("Y-m-t", strtotime($one->approvedate));
            $one->save();
            }
        }else{
            $one->approvedate = Null;
            $one->approvemonth = Null;
        }

        $one->save();

        // print_r($one->getErrors());

        // die;

    }
    else{


        }

    }       

}

谢谢!

当您检查该行是否已经存在以及当您从数据库加载它时,您正在执行非常相似的查询。

如果您希望新记录多于现有记录,您可以在循环之前将所有 skus 加载到数组中,然后检查 sku 是否在现有记录中。

for周期之前:

$existingSkus = Sku3d::find()
    ->select(['sku'])
    ->indexBy('sku')
    ->column();

然后在你的 for 循环中:

if (array_key_exists($test, $existingsSkus)) {
    $one = Sku3d::find()->where(['sku' => $test])->one();
    // ...
}

如果您预计导入中的大部分行已经存在于数据库中并且您要更新它们,那么您可以跳过 exists() 查询并直接加载数据。

$one = Sku3d::find()->where(['sku' => $test])->one();
if(!empty($one)) {
    // ... update existing row loaded in $one
} else {
    // ... create new row
}

代码中的另一个问题是您为每个更新的行多次调用保存。

if($one->datesubmit == NULL || $one->datesubmit == ""){
    $one->save(); //first save
} else {
    // ...
    $one->save(); //first save - else branch
}
// ...
if ($rowData[0][14] == "Approved"){
    $one->approvedate = $rowData[0][16];
    if ($one->approvedate == NULL || $one->approvedate == ""){
        $one->save(); // second save
    } else {
        $one->approvemonth=date("Y-m-t", strtotime($one->approvedate));
        $one->save(); //second save - else branch
    }
}else{
    $one->approvemonth = Null;
}
$one->save(); //third save when the previous condition is true, second save otherwise

您真的需要在完成所有更改之前调用保存吗?最后保存一次比每行保存 2 或 3 次要快。

此外,如果每次导入中有很多新行,您可能希望使用 batch insert 而不是为每一行创建和保存新模型。