2011-01-27 27 views
2

私は自分のプロジェクトでZend Frameworkを使用しています。私は複数のレコードを挿入する必要があり、私はZend_Dbが驚くほど低速なmy_sqlクエリ(数回)を見つけたので、私は何か間違ったと思っていました。 ここに2つの例があります。なぜ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;   

それは第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(); 

コード(私はこのような場合であっても引用符を使用しませんでした):

このコードはするmysql_queryで約0.065秒かかる

$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 />'; 

をここにいくつかの結果は以下のとおりです。

トランザクションの時間Zend_Db_Adapterのクエリ:0.23094701767 合計時間0.0949234962463 1 0.00199699401855が01を接続2 0.000336885452271 begin 3 0.000540018081665 INSERT INTO加入者(list_id、email_address、first_name、last_name、date_added、last_changed)VALUES(52,29、 '[email protected]'、 'John'、 'C​​linton'、 '2011- 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、 '[email protected]'、 'John'、 'C​​linton'、 '2011-01-28 15:25:21'、 '2011-01-28 15:25:21')

非常に奇妙です。 100レコードを挿入するためのトランザクションの時間は、すべてのクエリの実行の2.5倍です。 ループ内で文字列を作成するときに時間をかけてみると、クエリを削除しても時間がかかりません。

+0

大量のデータを持つ大きなシステムをお持ちの場合は、doctrine2をORM – Tjorriemorrie

+0

と見なすことができます。はい、データはかなり多くなります。しかし、Zend_Db_Adapterの問題はまだ分かりませんが、何がそんなに長くかかりますか? – Oleg

答えて

0

mysql_ *関数はPHPのネイティブなので非常に高速です。

Zend_Db_AdapterはPDOで作業しているので、PDOで最初の除去層、Zend_DB_Adapterで2番目の除去層があります。

レイヤの抽象化が進むほど、コードの速度が低下します。

なぜMVCフレームワークは一般に手続き型コードよりも遅いのですか?

、何回も)私は1つの理由は、あなたが($ DB->見積もりを実行することだと思い

+0

はい、私はそれが少し遅くなることを期待しましたが、いくつかの時間が遅く、それはあまりにも多くのようです。 I – Oleg

+1

そして、できるだけ高価なdb接続やクエリを避けるために、優れたサーバーサイドのキャッシュ戦略のメリットが強調されています。 –

+0

キャッシュがどのように複数の行を挿入するのに役立つか分かりません。 – Oleg

3

を機能*プリペアドステートメントおよびキャッシュ機構が再びあなたのベンチマークを試してみて、あなたはmysql_の近くでなければなりません不要です。 $ db-> quote()は引数として配列をとることができ、基本的に$ db-> quote()への呼び出しを1つに減らすことができます。さらに、mysql_queryバージョンでは$ dateAddedと$ lastChangedをエスケープしませんが、zend_dbバージョンではあなたはエスケープしません。

EDIT:あなたは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

私は、見積もりが引数として配列を取るとは思わなかった。私はドキュメンテーションでそれを見つけられませんでした。私は2番目のケースでも多くの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

関連する問題