2014-09-30 3 views
0

저는 일반적으로 PHP에서 많은 SQL 항목을 사용하지 않지만 최근에 친구가 디버그 할 수 있도록 강제되었습니다.PHP PDO MySQL 삽입 성능

일부 데이터를 삽입하기 위해 PHP로 PDO를 사용하고 있지만 삽입 성능은 매우 좋지 않습니다. 151 개의 인서트가 반복되는 간단한 루프가 거의 6 초 걸립니다! 그리고 왜 나는 길을 잃었습니다.

여기 내 코드입니다 : 나는 또한 bindParam를 사용하여 동일한 코드를 시도

<?php 

$database='XXXXXX'; 
$username='XXXXXX'; 
$password='XXXXXX'; 
$hostname='127.0.0.1'; 

$inserted=0; 
$counted=0; 
$dsn = 'mysql:dbname='.$database.';host='.$hostname.''; 
$start=microtime(true); 
try { 
    $data = new PDO($dsn, $username, $password, array(PDO::ATTR_EMULATE_PREPARES => false)); 
} catch (PDOException $e) { 
    echo('Connection failed: ' . $e->getMessage()); 
} 
for($i=1;$i<=150;$i++) { 
    $time=time(); 
    $query=$data->prepare("INSERT INTO `tbl_temp` (aid, bid) VALUES (?, ?)"); 
    $query->execute(array($i, $time)); 
} 
$data=null; 
print "Took: ".(microtime(true)-$start)." S to insert $i records\n"; 

// Took: 5.569482088089 S to insert 151 records <--- result 
?> 

과 속도가 거의 동일합니다. 서버에는 8 코어 Xeon 프로세서와 64GB RAM이 있습니다. 스크립트는 명령 줄 (php-cgi)에서 실행되며 데이터베이스와 테이블은 새롭고 비어 있습니다. 데이터베이스 타입은 InnoDB이다. 누가 왜 그렇게 느린지를 볼 올바른 방향으로 나를 가리킬 수 있습니까? 왜냐하면 MySQL은 결코 느리게 사용되지 않았기 때문입니다!

+5

루프 밖에서 sql을 준비하면 약간 도움이됩니다. 나는 당신의 테이블 구조에서 문제가 더 많이 발생한다고 생각한다. 테이블 구조와 현재 내용은 무엇입니까? –

+0

안녕하세요. 내 구조가이 ... 'code' ID입니다 -> AI 기본 키, 원조 -> INT, 입찰 -> Int 인 는 내 현재 내용은 : – user3169851

+0

그냥 제안이에 대한 설명을 할 수있어 ZERO 행 입니다 위 쿼리에서 병목 현상이 어디에 있는지 관찰합니다. 도움이 될 수도 있고 그렇지 않을 수도 있습니다 ... –

답변

0

Simon이 주석에서 언급했듯이, 루프 내에서 준비를하는 용도는 없습니다. 이렇게하면 데이터베이스에 300 개의 쿼리가 보내지며, 매번 준비 작업을 수행하고 실제 삽입 작업을 수행하게됩니다. 이전에 prepare 문을 사용하면 151 개의 쿼리 만 발생합니다.

$query = $data->prepare("INSERT INTO `tbl_temp` (aid, bid) VALUES (?, ?)"); 
for ($i = 1; $i <= 150; $i++) { 
    $time = time(); 
    $query->execute(array($i, $time)); 
} 

또 다른 아이디어는 결합 된 다중 삽입 문 대신 사용할 수 있습니다. 나는 그것이 더 나은 성능을 낼 수있을 것이라고 생각하지만, 확실하지 않다. :

$query = 'INSERT INTO `tbl_temp` (aid, bid) VALUES'; 
for ($i = 1; $i <= 150; $i++) { 
    if ($i == 1) { 
     $query .= ' ('.$i.', '.time().')'; 
    } else { 
     $query .= ', ('.$i.', '.time().')'; 
    } 
} 
$data->exec($query); 
+0

확인. 첫 번째 시도와 성능이 동일합니다.두 번째 시도는 바운드 매개 변수화를 수행하지 않으므로 시도 할 수 없습니다. 내 예제는 성능이 거의 같고 인서트 수가 대략 같지만 실제로 수행되는 작업을 줄인 버전입니다. – user3169851

0

SQL 서버 내부의 설정이 원인이라고 밝혀졌다. 지금까지 내가 거래를 말할 수있는 모든 쓰기에 디스크로 플러시 설정 커밋 :

innodb_flush_log_at_trx_commit=0 

이 새의 ACID 준수 설정이 기본 설치입니다.

나는 이것은 단지 정전 또는 OS 충돌이 mysqld에 충돌/트랜잭션 버퍼를 지우고 로그하지 않을 수 있습니다이

innodb_flush_log_at_trx_commit=2 

내 설정을 변경.

ACID의 "D"가 100 %가되어야하는 사람들에게는이 설정을 그대로 두어야합니다.

+0

... 또는 더 빠른 저장소를 사용하거나 암시 적 트랜잭션을 사용하지 마십시오. – symcbean

2

이 하나를 발견했습니다. Performance in PDO/PHP/MySQL: transaction versus direct execution. 그래서 이것을 시도하십시오.

$query = $data->prepare("INSERT INTO `tbl_temp` (aid, bid) VALUES (?, ?)"); 
try { 
     $data->beginTransaction(); 
     for($i=0; $i < 150; $i++) { 
      $time = time(); 
      $query->bindValue(1, $i, PDO::PARAM_INT); 
      $query->bindValue(2, $time, PDO::PARAM_STR); 
      $query->execute(); 
     } 
     $data->commit(); 
    } catch(PDOException $e) { 
      $data->rollBack(); 
    }