首页 > 解决方案 > Laravel 8 中的无效循环,每次迭代所花费的时间与数组大小成正比

问题描述

在 Laravel 8 / PHP 8 中,我在 POST 中收到一个正文,转换数据,然后批量插入 TimescaleDB。

这是代码:

public function store(Request $request)
    {
        ini_set('max_execution_time', -1);
        $body = $request->getContent();
        $meter = json_decode($body, true);
        $chunkSize = 1000;
        $measures = $meter['Measures'];
        $chunkedRaws = collect($measures)->chunk($chunkSize);
        $ok = 0;
        $nok = 0;
        $initialTime = Carbon::now();
        foreach ($chunkedRaws as $chunkNumber => $raws) {
            $chunkTime = Carbon::now();
            $rawsToInsert = [];
            foreach ($raws as $k => $raw) {
                $rawTime = Carbon::now();
                array_push($rawsToInsert, new \App\Models\Raw([
                    'operation_id' => $meter['OperationID'],
                    'meter_id' => $meter['ID'],
                    'conso_prod' => $meter['ConsoProd'],
                    'timestep' => $meter['Timestep'],
                    'unit' => $meter['Unit'],
                    'source' => $source,
                    'time' => Carbon::parse($raw['t'])->toIso8601ZuluString(),
                    'delta' => $raw['d'],
                ]));
               

            }
            // Insert into TimescaleDB cut
        }

        return response()->json(['message' => $ok . " Raws has been inserted,\n " . $nok . " Failed"], 200);
    }

我第一次调用它时,我有一个包含 3744 个元素的主体。

每个元素推入数组大约需要 5-6 毫秒,因此,大约 6 x 3744 / 1000 = 22 秒。

但我的第二篇文章有 26930 个元素。现在,每个array_push大约需要 52 毫秒,所以 52 * 26930 / 1000 = 23 分钟。路长。

应该总是相同的array_push,与 body 中有多少行无关?

为什么花费的时间array_push与大小成正比$chunkedRaws???

标签: phplaravelloopscollections

解决方案


您可以尝试在外部声明该对象。如上所述,您可以停止使用 array_push

...

$raw = new \App\Models\Raw([
    'operation_id' => $meter['OperationID'],
    'meter_id' => $meter['ID'],
    'conso_prod' => $meter['ConsoProd'],
    'timestep' => $meter['Timestep'],
    'unit' => $meter['Unit'],
    'source' => $source, 
]);

foreach ($chunkedRaws as $chunkNumber => $raws) {
    $chunkTime = Carbon::now();
    $rawsToInsert = [];
    foreach ($raws as $k => $raw) {
        $rawTime = Carbon::now();
        // Here I'm assuming you have setter in your Raw object
        $raw->setTime(Carbon::parse($raw['t'])->toIso8601ZuluString());
        $raw->setDelta($raw['d']);
        $rawsToInsert[] = $raw;
    }
    // Insert into TimescaleDB cut
}

...

推荐阅读