为什么 Zend_Db_Adapter 比 mysql_query 慢很多

发布于 2024-10-14 22:53:18 字数 7693 浏览 5 评论 0原文

我在我的项目中使用 Zend 框架。我需要插入多条记录,我发现 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) 值 (52, 29, '[电子邮件受保护]', '约翰', '克林顿', '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) 值 (52, 29, '[电子邮件受保护]', '约翰', '克林顿', '2011-01-28 15:25:21', '2011-01-28 15:25:21' )

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

I use Zend Framework in my project. I need to insert multiple records and I found that Zend_Db suprisingly slower thatn my_sql query (several times), that made me think I did something wrong.
Here are two examples.

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;

Example with 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;           

In the first case it took 14.8 seconds, in the second 3.7.
Could you tell me why does it happend and what do you do wrong?

If I delete any quote for Zend_Db it took 12 seconds from 14 with quote, but it's still much more slower than with 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;

Thank you for any information about this issue.

This code takes about 0.065 seconds with mysql_query:

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

Code with benchmark of Zend_Db_Adapter (I didn't even use quote in this case):

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

Here are some results:

Time of transaction Zend_Db_Adapter query: 0.23094701767
Total time 0.0949234962463
1 0.00199699401855 connect
2 0.000336885452271 begin
3 0.000540018081665 INSERT INTO subscribers (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')
4 0.000504016876221 INSERT INTO subscribers (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')

It's very strange. The time of transacation to insert 100 records is 2.5 times more than executing of all queries.
If I try to meach the time of forming strings in the loop it (if we delete query) doesn't take so much time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我纯我任性 2024-10-21 22:53:18

我认为原因之一是您执行 $db->quote() 的次数太多,这是不必要的。您是否知道 $db->quote() 可以将数组作为其参数,并且您基本上可以将对 $db->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)

I think that one reason is that you execute $db->quote() too many times, which is unnecessary. Do you know that $db->quote() can take an array as its argument and you can basically reduce calls to $db->quote() to only one. In addition in your mysql_query version you do not escape $dateAdded and $lastChanged, while in zend_db version you do.

EDIT: Added an example below

    $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)
獨角戲 2024-10-21 22:53:18

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

Zend_Db_Adapter 与 PDO 一起使用,因此您有第一个带有 PDO 的抽象层,第二个带有 Zend_DB_Adapter 的抽象层。

层抽象越多,代码速度就越慢。

这就是为什么 MVC 框架通常比过程代码慢的原因。

再次尝试使用准备好的语句和缓存机制进行基准测试,您应该接近 mysql_* 函数

mysql_* functions are natives to PHP , so they are very fast.

Zend_Db_Adapter is working with PDO so you have a first absraction layer with PDO and a second with Zend_DB_Adapter.

More layer abstraction you 've got , more the code is slowing down.

That why the MVC framework in general are more slower than procedural code.

Try again your benchmark with prepared statement and a cache mechanism and you should be close of the mysql_* functions

梦魇绽荼蘼 2024-10-21 22:53:18

这看起来像您在 Zend_Db 中没有元数据缓存。

This looks like you don't have a metadata cache in Zend_Db.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文