为什么Zend_Db_Adapter比mysql_query慢得多

时间:2011-01-27 09:07:22

标签: php mysql performance zend-framework zend-db

我在我的项目中使用Zend Framework。我需要插入多个记录,我发现Zend_Db在my_sql查询(几次)的速度惊人地慢了,这让我觉得我做错了。 这是两个例子。

Zend_Db_Adapter会:

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

mysql_query的示例:

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

在第一种情况下,花费了14.8秒,在第二种情况下为3.7。 你能告诉我它为什么会发生,你做错了什么?

如果我删除了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;

感谢您提供有关此问题的任何信息。

使用mysql_query:

,此代码大约需要0.065秒
    $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(); 

使用Zend_Db_Adapter基准测试的代码(在这种情况下我甚至没有使用引号):

    $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连接 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,'test_0@gmail.com','John','Clinton','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,29,'test_1 @ gmail.com','John','Clinton','2011-01-28 15: 25:21','2011-01-28 15:25:21')

这很奇怪。插入100条记录的交易时间是执行所有查询的2.5倍。 如果我尝试在循环中形成字符串的时间(如果我们删除查询)不花费那么多时间。

3 个答案:

答案 0 :(得分:3)

我认为一个原因是你执行$ db-&gt; quote()太多次了,这是不必要的。你知道$ db-&gt; quote()可以将数组作为参数,你基本上可以将对$ db-&gt; quote()的调用减少到只有一个。另外在你的mysql_query版本中,你没有转义$ dateAdded和$ lastChanged,而在你使用的是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)

答案 1 :(得分:0)

mysql_ *函数是PHP的原生函数,所以它们非常快。

Zend_Db_Adapter正在使用PDO,因此你有第一个带有PDO的抽象层,第二个带有Zend_DB_Adapter。

你有更多的图层抽象,代码越来越慢。

这就是为什么MVC框架通常比程序代码慢得多。

再次尝试使用预准备语句和缓存机制的基准测试,您应该关闭mysql_ *函数

答案 2 :(得分:0)

看起来你在Zend_Db中没有元数据缓存。