CSV 배열의 인코딩을 일괄적으로 변경하여 키 설정

15044 단어 PHPLaravel

개시하다


나는 CSV가 채택한 배열 인코딩을 바꾸는 기초 위에서 연상 배열화를 하고 싶다.
최종적으로 문자 코드를 UTF-8로 설정합니다.
수량이 적을 때는 문제가 없지만, 실제 데이터(10만기록·200열)가 유입됐을 때는 처리 속도가 유난히 빨라져 조정됐다.

해본 일

  • INSERT 처리를 한 줄에서 여러 줄로 변경
  • CSV 변환 처리 튜닝
  • 대량 삽입과 다중 삽입은 별것입니다.
    이번에 한 일은 넓은 의미로 여러 삽입물이지만, 한 번에 처리할 수 없어 여러 개와 벌크 조합처럼 느껴졌다.
    대량 삽입
    한 번에 여러 개의 삽입을 실행합니다.제출 횟수가 적고 처리가 빠르다.
    BEGIN;
    INSERT INTO tbl_name (a, b, c) VALUES (1, 2, 3);
    INSERT INTO tbl_name (a, b, c) VALUES (4, 5, 6);
    INSERT INTO tbl_name (a, b, c) VALUES (7, 8, 9);
    COMMIT;
    
    다중 삽입
    질의에 여러 줄 레코드를 삽입합니다.물론 한 번만 제출할 수 있다.
    BEGIN;
    INSERT INTO tbl_name (a, b, c) VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);
    COMMIT;
    

    배열


    csv-array
    /* SJIS-WIN */
    $csv_array = [
        0 => [
            0 => '1',
            1 => 'test user1',
            2 => '090-9999-9999',
            3 => '28',
            // more columns...
        ],
        1 => [
            0 => '2',
            1 => 'test user2',
            2 => '090-9999-9999',
            3 => '42',
            // more columns...
        ],
        // more rows...
    ];
    
    /* key array */
    $keys = [
        0 => 'id',
        1 => 'name',
        2 => 'phone',
        3 => 'age',
        // more keys...
    ];
    
    /* 最終的にほしい配列 */
    $rows = [
        0 => [
            'id'    => '1',
            'name'  => 'test user1',
            'phone' => '090-9999-9999',
            'age'   => '28',
            // more columns...
        ],
        1 => [
            'id'    => '2',
            'name'  => 'test user2',
            'phone' => '090-9999-9999',
            'age'   => '42',
            // more columns...
        ],
        // more rows...
    ];
    

    스트로크 연습


    인코딩 키 교체 처리
    $rows = [];
    foreach ($csv_array as $line => $csv_line) {
        foreach ($csv_line as $i => $buf) {
            $key               = $keys[$i];
            $rows[$line][$key] = mb_convert_encoding($buf, 'UTF-8', 'ASCII, JIS, UTF-8, EUC-JP, SJIS-win'); // ※1
        }
    }
    
    INSERT 처리
    
    try () {
        // トランザクション開始
        \DB::connection('mysql_sample')->beginTransaction();
        $table = \DB::connection('mysql_sample')->table('sample');
        foreach ($rows as $row) {
            // 1レコード追加
            $table->insert($row);
        }
        // 問題なければコミット
        \DB::connection('mysql_sample')->commit();
    } catch (\Exception $e) {
        // 問題が発生すればロールバック
        \DB::connection('mysql_sample')->rollback();
        echo $e->getTraceAsString();
    }
    

    수정 후


    인코딩 키 교체 처리
    /*
        配列をまとめてエンコーディングする
        PHP5.6・7.0・7.1だとバグがある点に注意する ※2
        変換結果は元の配列にセットされる
    */
    mb_convert_variables('UTF-8', 'SJIS-WIN', $csv_array);
    
    // キー配列を指定して一括置換
    $rows = array_combine($keys, $csv_array);
    
    
    INSERT 처리
    
    try () {
        // トランザクション開始
        \DB::connection('mysql_sample')->beginTransaction();
        $table = \DB::connection('mysql_sample')->table('sample');
        $bulk_counter = 0;  // カラム数カウンタ
        $bulk_rows    = []; // 一括INSERT用配列
        foreach ($rows as $row) {
            $counter     = count($row);
            $bulk_rows[] = $row;
            /*
              プリペアドステートメントは65536パラメータをオーバーするとエラーとなる ※3
              そのため、カラム数が規定値を上回った時点でINSERTを実行している
            */
            if ($counter + $bulk_counter > 65500) {
                $table->insert($bulk_rows);
                $bulk_rows    = [];
                $bulc_counter = 0;
            } else {
                $bulk_counter += $counter;
            }
        }
        if ($bulk_rows !== [null]) {
            $table->insert($bulk_rows);        
        }
        \DB::connection('mysql_sample')->commit();
    } catch (\Exception $e) {
        \DB::connection('mysql_sample')->rollback();
        echo $e->getTraceAsString();
    }
    
    

    주의 사항


    ※1:mb_convert_encoding의 문자 코드에 대한 명시 지정


    참조여기..
    세 번째 매개 변수의 $fromencoding에서 변환하기 전의 문자 인코딩 이름을 지정합니다. 만약 여기에서 'auto' 라고 지정하면 환경에 따라 달라집니다.
    Warning: mb_convert_encoding(): Unable to detect character encoding
    의 오류로 인해 문자 인코딩 변환이 실패할 수 있습니다.
    따라서 가능한 한 "auto"를 사용하지 말고 문자 인코딩을 지정하는 것을 권장합니다.

    ※2:mb_convert_variables 오류


    참조여기..
    PHP 5.6.30 or PHP 7.0.16 or PHP 7.1.1 현재 나타나는 버그의 모습은 수정 pull 요청을 받은 것 같습니다.

    ※ 3: 예매권 문구의 상한치를 한꺼번에 발행 가능


    여기.에 마음에 드는 기록이 있다.
    think the number of placeholders is limited to 65536 per query (at least in older mysql versions).
    (나는 자리 차지 문자의 수량 (적어도 오래된 mysql 버전에서는) 모든 검색이 65536로 제한되어 있다고 생각한다.)

    기타

  • MySQL 문장에도 발송 가능한 상한치(여기.가 있음
  • 주의

    10만 기록 / 200 열 INSERT 결과


    처리하다.
    타임
    반작용
    30분 초과
    수정 후
    5분 23초.

    감상


    INSERT의 대량의 데이터가 시간이 걸린다고 생각했다면 자신이 쓴 코드의 대부분이 사용된 것을 발견했다.
    나는 자신의 인코딩을 반성하면서 표준이 실현된 함수의 장점도 다시 느꼈다.

    좋은 웹페이지 즐겨찾기