2013-10-17 3 views
0

배열을 반복하는 foreach 루프가 있습니다.메모리/시간 효율적인 데이터베이스 항목

각 인스턴스에서 배열을 쿼리 문자열로 구성하고 MySQLi를 사용하여 데이터베이스에 추가합니다.

function storeProperties($data, $db) { 
    foreach ($data['property'] as $property) { 
     $query_string = "INSERT INTO table VALUES(..., ..., ...,)" 
     $db->query($query_string); 
     echo $db->error; 
    } 
} 

이 작업을 수행해야하는 더 나은 방법이 있습니까?
분명히이 방법은 n 데이터베이스 쿼리를 사용하므로 메모리 집약적이며 시간이 많이 걸립니다.

더 좋은 방법이 있나요? 각 쿼리를 단일 문자열로 연결하고 for 루프 외부에서 모두 실행해야합니까?

+0

concat 쿼리가 MySQL의 서버 (최대 1Mb) 설정에서 벗어나는 경우 계산해야하기 때문에 PHP concat는 메모리와 CPU 전원도 사용합니다. –

+0

예. 루프 내에서 전체 쿼리 문자열 ("INSERT INTO table VALUES"제외)을 작성한 다음 루프가 완료되면 실행하십시오. 그렇게하면 데이터베이스로의 왕복은 단 하나입니다. – Strawberry

답변

0

다음은 대량 삽입에 사용되는 내 PDO 작업 장치의 방법입니다. 여러 VALUES 항목이있는 단일 INSERT 문을 작성합니다.

(여기에 사용되는 몇 가지 방법은, 코드 조각에 포함되지 특히 $this->connect() (PDO에 연결) 방법이 복잡한 클래스 정의에서 싹둑가, $this->begin()이므로주의 해주십시오

$db->bulkinsert(
    'tbl_my_tablename', 
    array('fieldname_1','fieldname_2', 'fieldname_3'), 
    array(
     /* rec1 */ array('r1f1', 'r1f2', 'r1f3'), 
     /* rec2 */ array('r2f1', 'r2f2', 'r2f3'), 
     /* rec3 */ array('r3f1', 'r3f2', 'r3f3') 
    )); 

로 사용 $this->commit()$this->rollback()) 및 로깅을위한 정적 인 Log 클래스는 Apache Commons와 유사합니다 .-)

하지만 이것이 필요한 것 같습니다.

/** 
    * Performs fast bulk insertion 
    * Parameters: 
    *  $tablename 
    *  $datafields - non-assiciative array of fieldnames 
    *     or propertynames if $data is an array of objects 
    *  $data  - array of either non-associative arrays (in the correct order) 
    *     or array of objects with property names matching the $datafields array 
    */ 
    const MAX_BULK_DATA = 3000; 
    public function bulkinsert($tablename, $datafields, &$data) { 
     $result = 0; 
     try { 
      try { 
       $this->connect(); 
       $datacount = count($data); 
       // loop until all data has been processed 
       $start = 0; 
       $lastbinds = 0; 
       $this->begin(); 
       while ($start < $datacount) { 
        $ins = array(); 
        $bindscount = min(self::MAX_BULK_DATA, $datacount - $start); 
        if ($bindscount != $lastbinds) { 
         // prepare the binds 
         $binds = substr(str_repeat(',?', count($datafields)), 1); 
         $binds = substr(str_repeat(",($binds)", $bindscount), 1); 
         $lastbinds = $bindscount; 
        } 
        for ($go = $start, $last = $start + $bindscount; $go < $last; $go++) { 
         if (is_object($data[$go])) { 
          try { 
           foreach($datafields as $propname) { 
            $rfl = new ReflectionProperty($data[$go], $propname); 
            $rfl->setAccessible(true); 
            $ins[] = $rfl->getValue($data[$go]); 
           } 
          } 
          catch(ReflectionException $e) { 
           throw new InvalidArgumentException('PDOCONNECT_ERR_SQL_UNKNOWN_PROPERTY', 0, $e); 
          } 
         } 
         else { 
          foreach($data[$go] as $value) { 
           $ins[] = $value; 
          } 
         } 
        } 
        $sql = sprintf('INSERT INTO %s (%s) VALUES %s', $tablename, join(',',$datafields), $binds); 
        Log::trace($sql); 
        $stmt = $this->pdo->prepare($sql); 
        $stmt->execute($ins); 
        $start = $last; 
        $result += $bindscount; 
       } 
       $this->commit(); 
      } 
      catch(PDOException $e) { 
       // do something with the exception if necessary 
       throw $e; 
      } 
     } 
     catch(Exception $e) { 
      $this->rollback(); 
      throw $e; 
     } 
     return $result; 
    } 
} 
관련 문제