엑셀 10만건 디비 등록중 페이지가 ERR_TIMED_OUT 되요

엑셀 10만건 디비 등록중 페이지가 ERR_TIMED_OUT 되요

QA

엑셀 10만건 디비 등록중 페이지가 ERR_TIMED_OUT 되요

본문

excel_file.php

excel_upload.php

그누보드/lib/PHPExcel/IOFactory.php  활용

엑셀파일  10만건

 

10만건 등록을 진행하면 통상 10~60분 이상도 걸립니다

즉, 브라우저가 중간에 TIME_OUT 이 발생하게 됩니다

물론 상품은 서버에서 계속 등록중입니다

phpMyAdmin 에서 SHOW PROCESSLIST; 로 확인해보면 열일중이죠

 

상품이 등록되는 동안 서버와 소통하면서 상황이 업데이트 되면서 이용자와 소통해야하나 고민중입니다

아래는 테스트에 필요한 요소만 최대한 정리해서 올렸습니다

아래내용을 다른 엑셀 등록에 응용하시면 나름 좋은 학습자료가 될 수 있습니다

 

iframe 을 넣어서 거기에 서버와 소통하는 ajax 를 만들까 하는 생각도 해보고

일단 파일이 업로드 되고, 디비에 등록 시작되면 등록중, 페이지를 닫으세요 라는 내용을 띄울까도 생각해보고

여러가지 방법을 찾아보는 중입니다

이와 관련하여 참고할 정보나 아이디어가 있다면 조언 부탁드립니다

 

 

1. 디비 테이블

item 테이블 칼럼

   item_idx   int(11) auto_increment

   item_barcode   varcha(255)

   item_barcode  varcha(255)

   item_title  varcha(255)

   item_quanitiy  varcha(255)

   item_price   varcha(255)

   

item_history 테이블 칼럼
   item_barcode   varcha(255)
   item_title   varcha(255)
   item_quanitiy   varcha(255)
   item_price   varcha(255)

 

 

2. 엑셀파일 셀 정보  ( 엑셀 파일은 B1 에는 다른 행에 동일한 것이 n개 존재합니다 )

A1 = it_id   순서
B1 = BARCODE   제품번호
C1 = DESCRIPTION   상품명
D1 = QUANTITY      수량
E1 = price        금액

 

 

3. excel_file.php

<?php
include_once("_common.php");

$g5['title'] = '엑셀파일로 상품 대량 등록';
include_once(G5_PATH.'/head.php');

add_stylesheet('<link rel="stylesheet" href="./excel.css">', 0);
?>

    <form name="fitemexcel" method="post" action="./excel_upload.php" enctype="MULTIPART/FORM-DATA" autocomplete="off">
        <div id="excelfile_upload">
            <label for="excelfile">파일선택</label>
            <input type="file" name="excelfile" id="excelfile">
        </div>

        <div class="win_btn btn_confirm">
            <input type="submit" value="상품 엑셀파일 등록" class="btn_submit btn">
        </div>
    </form>
</div>

<?php
include_once(G5_PATH.'/tail.php');
 

 

4. excel_upload.php

<?php
//ini_set('memory_limit','512M'); // 메모리 512MB 사용 
ini_set('memory_limit','-1'); // 메모리 무제한 사용

include_once("_common.php");


$g5['title'] = '엑셀파일로 상품 대량 등록 결과';
include_once(G5_PATH.'/head.php');

 

$upload_max_filesize = ini_get('upload_max_filesize');

// 업로드 허용용량
$upload_size_MB = "20"; // MB
$upload_size_BY = "1048576"; // Byte
$upload_size = $upload_size_MB * $upload_size_BY;
//$upload_size = "20971520"; // 20MB x 1 MB x 1,048,576 bytes

$tmp_file  = $_FILES['excelfile']['tmp_name'];
$filesize  = $_FILES['excelfile']['size'];
$filename  = $_FILES['excelfile']['name'];

$filename  = get_safe_filename($filename);

//echo "filename = {$filename}<br>";
//echo "upload_max_filesize = {$upload_max_filesize}<br>";
//echo "error = {$_FILES['excelfile']['error']}<br>";

// 서버에 설정된 값보다 큰파일을 업로드 한다면
if ($filename) {
    if ($_FILES['excelfile']['error'] == 1) {
        $file_upload_msg .= '\"'.$filename.'\" 파일의 용량이 서버에 설정('.$upload_max_filesize.')된 값보다 크므로 업로드 할 수 없습니다.\\n';
        alert($file_upload_msg);
    //    continue;
    }
    else if ($_FILES['excelfile']['error'] != 0) {
        $file_upload_msg .= '\"'.$filename.'\" 파일이 정상적으로 업로드 되지 않았습니다.\\n';
        alert($file_upload_msg);
    //    continue;
    }
}

if (is_uploaded_file($tmp_file)) {
    // 설정한 업로드 사이즈보다 크다면 건너뜀
    if ($filesize > $upload_size) {
        $file_upload_msg .= '\"'.$filename.'\" 파일의 용량('.number_format($filesize).' 바이트)이 '.number_format($upload_size).' 바이트 보다 크므로 업로드 하지 않습니다.\\n';
        alert($file_upload_msg);
    //    continue;
    }
}

add_stylesheet('<link rel="stylesheet" href="./excel.css">', 0);

include_once(G5_LIB_PATH.'/PHPExcel/IOFactory.php');

$objPHPExcel = PHPExcel_IOFactory::load($tmp_file);
$sheet = $objPHPExcel->getSheet(0); // 첫번째 시트 데이타 추출

$num_rows = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();

$dup_it_id   = array();
$fail_it_id  = array();
$dup_count   = 0;
$total_count = 0;
$fail_count  = 0;
$succ_count  = 0;

// 실 데이타가 2번행부터 시작되므로 $i = 2
for ($i = 2; $i <= $num_rows; $i++) {
    $total_count++;

    $j = 0;

    $rowData = $sheet->rangeToArray('A' . $i . ':' . $highestColumn . $i,
                                        NULL,
                                        TRUE,
                                        FALSE);

    $it_id           = addslashes($rowData[0][$j++]); // A
    $BARCODE         = addslashes($rowData[0][$j++]); // B
    $DESCRIPTION     = addslashes($rowData[0][$j++]); // C
    $QUANTITY        = addslashes($rowData[0][$j++]); // D
    $price          = addslashes($rowData[0][$j++]); // E


    // 필드에 값이 있는지 확인해서 있을때만 작업시작
    if ($BARCODE) {
        // $BARCODE 중복체크
        $sql_cnt1 = " select count(*) as cnt from `item` where item_barcode = '{$BARCODE}' ";
        $sql_cnt1 .=" limit 1 ";
        //echo "sql_cnt1 = {$sql_cnt1}<br>";
        $row_cnt1 = sql_fetch($sql_cnt1);
        
        // 신규 등록일때
        if($row_cnt1['cnt'] == 0) {
            //echo "신규 {$BARCODE} {$DESCRIPTION} <br>";
            sql_query( " 
                insert into `item` set
                    item_barcode  = '{$BARCODE}' ,
                    item_title    = '{$DESCRIPTION}' , 
                    item_quanitiy = '{$QUANTITY}' ,
                    item_price   = '{$price}'
            ");
            //sql_query($sql);
            //echo "sql_insert = {$sql}<br>";

            sql_query( " 
                insert into `item_history` set
                    item_barcode  = '{$BARCODE}' ,
                    item_title    = '{$DESCRIPTION}' , 
                    item_quanitiy = '{$QUANTITY}' ,
                    item_price   = '{$price}' 
            ");
            //sql_query($sql);
            //echo "sql_history = {$sql}<br>";
            $succ_count++;
        } else { // 중복일때
            //echo "중복 {$BARCODE} {$DESCRIPTION} <br>";
            //$fail_it_id[] = $it_id;
            //$dup_it_id[]  = $BARCODE;
            $dup_count++;
            //$fail_count++;
            //continue;
        }
    }
}
?>
<div class="new_win">
    <div class="local_desc01 local_desc">
        <p><?php echo $filename; ?> 상품등록을 완료했습니다.</p>
    </div>

    <dl id="excelfile_result">
        <dt>총상품수</dt>
        <dd><?php echo number_format($total_count); ?></dd>
        <dt>완료건수</dt>
        <dd><?php echo number_format($succ_count); ?></dd>
        <?php /* ?>
        <dt>실패건수</dt>
        <dd><?php echo number_format($fail_count); ?></dd>
        <?php if($fail_count > 0) { ?>
        <dt>실패상품코드</dt>
        <dd><?php //echo implode(', ', $fail_it_id); ?></dd>
        <?php } ?
        <?php */ ?>
        <?php //if($dup_count > 0) { ?>
        <dt>중복건수</dt>
        <dd><?php echo number_format($dup_count); ?></dd>
        <?php /* ?>
        <dt>중복상품코드</dt>
        <dd><?php echo implode(', ', $dup_it_id); ?></dd>
        <?php */ ?>
        <?php //} ?>
    </dl>

</div>

<?php
include_once(G5_PATH.'/tail.php');

이 질문에 댓글 쓰기 :

답변 3

10만건을 insert하는걸 대기하는게 문제겠네요

 

처리방식을 좀 변경해보세요

 

1. 업로드

2. 브라우저에는 상태는 처리중으로 회신종료

3. 업로드된 엑셀 insert로직 작동 (서버의 배치작동으로) - 작동시작시점은 서버에서 판단하도록 설정 (시간별체크라던지...)

4. 엑셀자료 insert종료시 처리중상태를 업로드완료로 상태변경 

5. 업로드된 데이타 조회가능처리

 

로 하면되지 않을까싶네요

 

insert작업중에 브라우저와의 통신을 최대한 배제 하시는게 좋습니다.

브라우저에는 상태는 처리중으로 회신종료
요 처리가 ... 엑셀 1열씩 처리하면서 브라우저는 계속 빈화면, 결과를 기다리는 중이 되더라구요.
화면에 다른 메시지를 뿌리는 방법을 찾아봐야겠군요
감사합니다

가능하다면

cvs로 바꾸어서

서버에서 mysql로 작업하시는 것을 추천합니다.

매장 매니저가 스스로 등록을 할 수 있어야 해서요...
물론 매장 매니저는 많아야 3~5만건 정도이기는 하지만요
어휴 고민이네요.  함께 고민해주셔서 감사합니다

웹브라우저 기본 타임아웃이 있기 때문에

시간이 오래걸리는 작업은 서버에서 별도 프로세스로 동작시키는게 낫습니다.

 

이런 경우 웹브라우저 기반으로 동작시키려면

시간이 오래걸리지 않도록 잘게 쪼개어 실행시키는 방식으로 변경하거나

별도 프로세스에서 동작시키고

진행률을 표시하거나 확인할수 있는 방법을 제공해주는 방법정도가 좋을것 같습니다.

파일 스트림으로부터 대량의 데이터를 삽입 시 Load Data Local Infile 구문을 이용해서 필드 구문자로 정리된 File을 MySQL DB로 Redirection 시킬 수 있습니다.
각각에 대한 Insert 구문 수행보다 빠른 퍼포먼스를 보입니다.

라는 글이 보이는데, 저것에 대해서 연구해봐야겠네요.
감사합니다

Load Data Local Infile 구문을 사용한다고 해도
데이터를 등록할 기본적인 양이 많아 버리면 별 성능향상은 기대하기 힘들것 같고
오히려 그 구문을 사용함으로 인한 설정관련 에러 대응하면서 문제해결시간도 늦어지고 해결도 제대로 안될수 있습니다.

답변을 작성하시기 전에 로그인 해주세요.
전체 123,527 | RSS
QA 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT