2011-01-27 2 views
2

저는 프로젝트에서 Zend Framework를 사용합니다. 나는 여러 레코드를 삽입해야하고 Zend_Db가 놀랍게도 느린 그 my_sql 쿼리 (여러 번)를 발견했기 때문에 내가 잘못 생각했다고 생각했습니다. 두 가지 예가 있습니다.Zend_Db_Adapter가 mysql_query보다 훨씬 느린 이유

Zend_Db_Adapter :와는 mysql_query

 $startTime = microtime(true); 
     $db = Zend_Db_Table::getDefaultAdapter(); 
     $db->beginTransaction(); 

     $dateAdded = date('Y-m-d H:i:s'); 
     $lastChanged = $dateAdded;     

     foreach ($importDataNamespace->data as $subscriberNum => $subscriber) 
     { 
      foreach ($fieldsMap as $fieldNumber => $fieldTag) { 
       if (isset($subscriber[$fieldNumber])) { 
        $subscriberData[$fieldTag] = $subscriber[$fieldNumber]; 
       } else { 
        $subscriberData[$fieldTag] = ''; 
       } 
      } 
      $query = 'INSERT INTO subscribers (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) ' . 
        'VALUES (' . 52 . ', ' . 29 . ', ' . $db->quote($subscriberData['EMAIL']) . ', ' . $db->quote($subscriberData['FNAME']) . 
        ', ' . $db->quote($subscriberData['LNAME']) . ', ' . $db->quote($dateAdded) . ', ' . $db->quote($lastChanged) . ')'; 
      $db->query($query);                 
     } 
     $db->commit(); 

     $this->view->time = microtime(true) - $startTime; 

예 : 첫 번째 경우

 $startTime = microtime(true); 

     $user = 'root'; 
     $password = 'password'; 
     $db = 'database'; 
     $connect = @mysql_connect('localhost',$user,$password) or die("Failed to connect database"); 
     @mysql_select_db($db) or die("Failed to select database");   

     $dateAdded = date('Y-m-d H:i:s'); 
     $lastChanged = $dateAdded;  

     $result = mysql_query('SET autocommit = 0');    

     foreach ($importDataNamespace->data as $subscriberNum => $subscriber) 
     { 
      foreach ($fieldsMap as $fieldNumber => $fieldTag) { 
       if (isset($subscriber[$fieldNumber])) { 
        $subscriberData[$fieldTag] = $subscriber[$fieldNumber]; 
       } else { 
        $subscriberData[$fieldTag] = ''; 
       } 
      } 
      $query = 'INSERT INTO subscribers (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) ' . 
       'VALUES (' . 52 . ', ' . 29 . ', \'' . mysql_real_escape_string($subscriberData['EMAIL']) . '\', \'' . mysql_real_escape_string($subscriberData['FNAME']) . 
       '\', \'' . mysql_real_escape_string($subscriberData['LNAME']) . '\', \'' . $dateAdded . '\', \'' . $lastChanged . '\')';      
      mysql_query($query);          
     } 
     $result = mysql_query('SET autocommit = 1'); 
     $result = mysql_query('COMMIT;'); 

     $this->view->time = microtime(true) - $startTime;   

IT는 3.7 초, 14.8 초 걸렸다. 왜 그런 일이 일어나고 무엇이 잘못 되었습니까? 내가 Zend_Db에 대한 모든 견적을 삭제하면

은 견적 14 12 개 초 걸렸습니다,하지만 여전히하여 mysql_query보다 느린 훨씬 더 :
 $startTime = microtime(true); 
     $db = Zend_Db_Table::getDefaultAdapter(); 
     $db->beginTransaction(); 

     $dateAdded = date('Y-m-d H:i:s'); 
     $lastChanged = $dateAdded;     

     foreach ($importDataNamespace->data as $subscriberNum => $subscriber) 
     { 
      foreach ($fieldsMap as $fieldNumber => $fieldTag) { 
       if (isset($subscriber[$fieldNumber])) { 
        $subscriberData[$fieldTag] = $subscriber[$fieldNumber]; 
       } else { 
        $subscriberData[$fieldTag] = ''; 
       } 
      } 
      $query = 'INSERT INTO subscribers (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) ' . 
        'VALUES (' . 52 . ', ' . 29 . ', \'' . $subscriberData['EMAIL'] . '\', \'' . $subscriberData['FNAME'] . 
        '\', \'' . $subscriberData['LNAME'] . '\', \'' . $dateAdded . '\', \'' . $lastChanged . '\')'; 
      $db->query($query);               
     } 
     $db->commit(); 

     $this->view->time = microtime(true) - $startTime; 

이 문제에 대한 정보 주셔서 감사합니다. Zend_Db_Adapter의 벤치 마크와

$dateAdded = date('Y-m-d H:i:s'); 
    $lastChanged = $dateAdded;  

    $startTime = microtime(true);  
    $result = mysql_query('BEGIN'); 
    for ($i = 0; $i < 100; $i++) { 
     $email = 'test_ ' . $i . '@gmail.com'; 
     $query = 'INSERT INTO subscribers (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) ' . 
       'VALUES (' . 52 . ', ' . 29 . ', \'' . mysql_real_escape_string($email) . '\', \'' . mysql_real_escape_string($firstName) . 
       '\', \'' . mysql_real_escape_string($lastName) . '\', \'' . mysql_real_escape_string($dateAdded) . '\', \'' . mysql_real_escape_string($lastChanged) . '\')';                 
     mysql_query($query);    
    }    
    $result = mysql_query('COMMIT'); 
    $time = microtime(true) - $startTime;       
    echo 'Using mysql_query: ' . $time . '<br />'; 
    exit(); 

코드 (나는이 경우에도 따옴표를 사용하지 않은) : 여기

$db = Zend_Db_Table::getDefaultAdapter(); 
    $db->getProfiler()->setEnabled(true); 
    $profiler = $db->getProfiler();   

    $startTime = microtime(true); 
    $db->beginTransaction();   
    for ($i = 0; $i < 100; $i++) 
    { 

     $email = 'test_' . $i . '@gmail.com'; 
     $query = 'INSERT INTO subscribers (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) ' . 
      'VALUES (' . 52 . ', ' . 29 . ', \'' . $email . '\', \'' . $firstName . 
      '\', \'' . $lastName . '\', \'' . $dateAdded . '\', \'' . $lastChanged . '\')'; 
     $db->query($query);         
    }   
    $db->commit(); 
    $time = microtime(true) - $startTime;      
    echo 'Time of transaction Zend_Db_Adapter query: ' . $time . '<br />'; 

    echo 'Total time ' . $profiler->getTotalElapsedSecs() . '<br />';   
    $count = 0; 
    $totalTime = 0; 
    foreach ($profiler->getQueryProfiles() as $query) { 
     $count++; 
     $elapsedTime = $query->getElapsedSecs(); 
     $totalTime += $elapsedTime; 
     echo $count . ' ' . $elapsedTime . ' ' . $query->getQuery() . '<br />'; 
    } 
    echo 'Sum time: ' . $totalTime . '<br />'; 

어떤 결과입니다

이 코드는 mysql_query 약 0.065 초 정도 걸립니다 :

트랜잭션 시간 Zend_Db_Adapter 쿼리 : 0.23094701767 총 시간 0.0949234962463 1 0.00199699401855 2 0.000336885452271 시작 3 0.000540018081665 INSERT INTO 가입자 (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) VALUES (52, 29, '[email protected]', 'John', 'Clinton' 01-28 15:25:21 ','2011-01-28 15:25:21 ') 4 0.000504016876221 INSERT INTO 가입자 (list_id, account_id, email_address, first_name, last_name, date_added, last_changed) VALUES (52, 29, '[email protected]', 'John', 'Clinton', '2011-01-28 15:25:21', '2011-01-28 15:25:21')

매우 이상합니다. 모든 레코드를 삽입하기위한 트랜잭션의 시간은 모든 쿼리를 실행하는 것보다 2.5 배 더 큽니다. 루프에서 문자열을 형성하는 시간을 측정하려고하면 쿼리를 삭제할 때 시간이 많이 걸리지 않습니다.

+0

많은 양의 데이터가있는 큰 시스템을 사용하는 경우 doctrine2를 ORM – Tjorriemorrie

+0

으로 간주 할 수 있습니다. 예, 데이터가 많습니다. 그러나 Zend_Db_Adapter 문제는 아직 명확하지 않습니다. 왜 그렇게 오래 걸릴지 모릅니다. – Oleg

답변

0

mysql_ * 함수는 PHP의 원천이므로 매우 빠릅니다.

Zend_Db_Adapter는 PDO로 작업하므로 PDO가있는 첫 번째 결절 레이어와 Zend_DB_Adapter가있는 첫 번째 결절 레이어가 있습니다.

더 많은 레이어 추상화를 사용하면 더 많은 코드가 느려집니다.

일반적으로 MVC 프레임 워크가 일반적으로 절차 코드보다 속도가 느린 이유는 무엇입니까?

다시 준비된 명령문 및 캐시 메커니즘을 사용하여 벤치 마크를 시도하고 당신은 mysql_로 * 기능 나는 이유 중 하나는 당신이 실행하는 것이라고 생각

+0

예, 약간 느린 것으로 예상했지만 몇 시간 느려졌습니다. 너무 많이 보입니다. I – Oleg

+1

그리고 가능한 값 비싼 db 연결 및 쿼리를 피하기 위해 좋은 서버 측 캐싱 전략의 장점을 분명히 강조합니다. –

+0

캐싱이 어떻게 여러 행을 삽입하는 데 도움이되는지 잘 모르겠습니다. – Oleg

3

의 근접해야합니다 $ DB-> 따옴표() 너무 많이, 어떤 불필요합니다. $ db-> quote()가 배열을 매개 변수로 취할 수 있고 기본적으로 $ db-> quote()에 대한 호출을 하나만 줄일 수 있다는 것을 알고 계십니까?또한 mysql_query 버전에서는 $ dateAdded 및 $ lastChanged를 이스케이프 처리하지 않고 zend_db 버전에서는 이스케이프 처리하지 않습니다.

편집 : 당신이 Zend_Db의 메타 데이터 캐시가없는 것처럼이 보이는

$db = Zend_Db_Table::getDefaultAdapter(); 

    $input = array(
     'a' => "asd'lfksd", 
     'b' => "asdlfk'sdfasdf", 
     'c' => "asd fds f saf'sdfsd", 
     'd' => "asd fds f saf'sdfsd" 
    ); 


    // separate calls to quote 
    $startTime = microtime(true); 
    $db->quote($input['a']); 
    $db->quote($input['b']); 
    $db->quote($input['c']); 
    $db->quote($input['d']); 
    $totalTime1 = microtime(true) - $startTime; 



    // one call to quote 
    $startTime = microtime(true); 
    $db->quote($input); 
    $totalTime2 = microtime(true) - $startTime; 

    // show results 
    var_dump("Sperate calls are ". $totalTime1/$totalTime2 . " times slower"); 
    //output: string 'Sperate calls are 3.0875831485588 times slower' (length=46) 
+0

네, 고치려고합니다. 고마워요. – Oleg

+0

견적에는 시간이 많이 걸릴 것으로 생각하십니까? – Oleg

+0

나는 인수가 배열을 취할 수 있다고 생각하지 않았다. 문서에서 찾지 못했습니다. 두 번째 경우에도 많은 mysqli_real_escape_string을 사용했습니다. – Oleg

0

아래의 예를 추가했습니다.

+0

제발, 그게 무슨 뜻인지 설명해 주시겠습니까? – Oleg

+0

Zend_Db에서 메타 데이터 캐시에 대한 의미를 설명해 주시겠습니까? – Oleg

+0

http://framework.zend.com/manual/en/zend.db.table.html#zend.db.table.metadata.caching에서 자세한 내용을 볼 수 있습니다. 다행히도 청어가 될 수 있지만 문제 해결에 도움이되기를 바랍니다. 나는 쓸모없는 쿼리가 DB로 보내지는 것을 막기 위해 항상 Zend_Db에서 메타 데이터 캐시를 사용하는 습관을 갖습니다. – Julian