Laravel mongodbデータエクスポートcsv方式テスト

39129 ワード

データ量:10 w
需要:オーダー表関連ロット表エクスポートライン管理データ
jenssegers/mongodbを応用してパケットアクセスデータを拡張することは便利ですが、パフォーマンスの問題をもたらすのではないでしょうか.

jenssegers/mongodb拡張エクスポートの適用


ツール/環境:homestead+jenssegers/mongodb":"^3.2+console
$t = microtime(true);
    $order_id  = '';
    $is_true = true;
	$limit = 1000;
    $file_name = storage_path('files/csv_test.csv');
    $fp = fopen($file_name, 'w');
    while ($is_true) {
        $query = \App\Models\Order_test::query()
            ->with('batch')
            ->where('payment.status', '>', \App\Models\Order::PAYMENT_UNPAID);
        if (!empty($order_id)) {
            $query->where('id','>', $order_id);
        }
        $orders      = $query->orderBy('id', 'asc')->limit($limit)->get();
        $order_count = count($orders);
        if ($order_count > 0) {
            // 
            if (empty($order_id)) {
                fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
                $title_list = [
                    ' ',
                    ' ',
                    ' ',
                    ' ',
                    ' ',
                    ' ',
                    ' 1',
                    ' 2',
                    ' '
                ];
                fputcsv($fp, $title_list);
            }
            // 
            foreach ($orders as $order) {
                $order_id = $order['id']; 
                $data = [
                    'order_id'      => $order_id.'\t',
                    'pay_time'      => $order->pay_time ?? '',
                    'order_status'  => \App\Models\Order::$_statusArr[$order->status] ?? '',
                    'products_cost' => $order->products_cost,
                    'cost_total'    => $order->total,
                    'items_total'   => $order->items_total,
                    'batch_field1'  => $order->batch['field1']??'';,
                    'batch_field2'  => $order->batch['field2']??'';,
                    'created_at'    => (string)$order->created_at,
                ];

                fputcsv($fp, $data);
            }
        }

        // 
        if ($order_count < $limit) {
            $is_true = false;
            // 
            fclose($fp);
        }

    }

    $tl = microtime(true)-$t;
    dd($tl);

使用時間73 s

オリジナルエクスポート


ツール/環境:homestead+console
Artisan::command('tiway:mongo_raw', function () {

    $t = microtime(true);
    // mongo
    $con = new \MongoDB\Client("mongodb://username:password@host:port/");
    $db = $con->selectDatabase('test');
    $collection = $db->selectCollection('order_test');

    $order_id  = '';
    $is_true   = true;
    // 
    $limit_item = 1000;
    $file_name = storage_path('files/mongo_raw.csv');
    $fp = fopen($file_name, 'w');
    while ($is_true) {
        // 
        if (empty($order_id)) {
            fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
            $title_list = [
                    ' ',
                    ' ',
                    ' ',
                    ' ',
                    ' ',
                    ' ',
                    ' 1',
                    ' 2',
                    ' '
                ];
            fputcsv($fp, $title_list);
        }

        $pipeline = [];
        $match = ["payment.status" => ['$gt'=> \App\Models\Order::PAYMENT_UNPAID]];
        if (!empty($order_id)) {
            $order_id_match = ["id" => ['$gt'=> $order_id]];
            $match += $order_id_match;
        }
        array_push($pipeline,['$match' => $match]);
        $sort = [
            '$sort' =>['id'=>1],
        ];
        $limit = [
            '$limit'=>$limit_item
        ];
        array_push($pipeline,$limit,$sort);
        // batch
        $batch_pipe = [
            '$lookup' => [
                "from"         => "easyeda_batch",
                //  order 
                "localField"   => "batch_num",
                // user  
                "foreignField" => "batch_num",
                // order  
                "as"           => "batch",
            ],
        ];
        array_push($pipeline,$batch_pipe);
        // 
        $allow_disk = ['allowDiskUse'=> true];
        $orders = $collection->aggregate($pipeline,$allow_disk);
        $row = 0;
        // 
        foreach ($orders as $order) {
            $order_id = $order->id;
            $data = [
                    'order_id'      => $order_id.'\t',
                    'pay_time'      => $order->pay_time ?? '',
                    'order_status'  => \App\Models\Order::$_statusArr[$order->status] ?? '',
                    'products_cost' => $order->products_cost,
                    'cost_total'    => $order->total,
                    'items_total'   => $order->items_total,
                    'batch_field1'  => $order->batch['field1']??'';,
                    'batch_field2'  => $order->batch['field2']??'';,
                    'created_at'    => (string)$order->created_at,
                ];
            $row ++;
            fputcsv($fp, $data);
        }
        // 
        if ($row < $limit_item) {
            $is_true = false;
            // 
            fclose($fp);
        }
    }

    $tl = microtime(true)-$t;
    dd($tl);

});

なんと172 sも使っていたのに、もっと多くなった!!
[‘allowDiskUse’=>true]という設定のせいだと推測されますが、trueに設定しないとメモリが足りませんね.
In Aggregate.php line 219:

  Sort exceeded memory limit of 104857600 bytes, but did not opt in to external
  sorting. Aborting operation. Pass allowDiskUse:true to opt in.


s o r t用sort用sort用skipでページングしないでください.
そして...
書き出しは37000条の時点で172 sを超え、そしてどんどんゆっくりと...翌日発見:2213 s!!!what?!!!
簡単にSkipを使ってクエリーをしないでください.そうしないと、データ量が大きくなると性能が急激に低下します.これはSkipが1本1本数えているので、多くなると自然に遅くなります.
mongodb集約ドキュメントの探索中...