PDO插入查询会降低网站速度

时间:2012-03-26 23:10:58

标签: php mysql nginx pdo innodb

在我的网站上,我编写了一个功能,可以显示每天访问的访问者数量和浏览量。

问题是有时插入查询需要永远,而InnoDB中没有DELAYED INSERT函数。

编辑: 正在使用InnoDB,我的意思是加载时间长约6秒而不是0.1-0.5秒。一旦我删除了日志记录,网站就会快得多。

下面的$b数组包含浏览器信息,但根据XHProf,它的PDO查询需要很长时间才能执行。

插入代码是:

$values = array(
        'time' => time(),
        'ip' => $_SERVER['REMOTE_ADDR'],
        'page' => rtrim((isset($_GET['q']) ? $_GET['q'] : 'index'), '/'),
        'browser' => $b[11][0] . ' ' . $b[11][1],
        'os' => $uos,
        'referred' => (isset($_SERVER['HTTP_REFERER']) && !preg_match('|^' . Config::getValue('site', 'url') . '|', $_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''),
    );

    $this->table->insert($values);

和插入功能代码:

public function insert($table, $data) {
    ksort($data);

    $fieldNames = implode('`, `', array_keys($data));
    $fieldValues = ':' . implode(', :', array_keys($data));

    $sth = $this->prepare('INSERT INTO ' . $table . '(`' . $fieldNames . '`) VALUES (' . $fieldValues . ');');

    foreach ($data as $key => $value) {
        $sth->bindValue(':' . $key, $value);
    }

    $sth->execute();
}

4 个答案:

答案 0 :(得分:1)

“在我的网站上,我编写了一个功能,可以显示每天访问的访问者数量和浏览量。”

您是否正在为每个页面请求执行实时查询?这可能是它自己的性能问题。如果您每小时左右查询这些数字,并且缓存该值,它不会杀死任何人。然后,后续页面视图可以使用缓存值而不是实时值。

“问题是有时插入查询需要永远,而InnoDB中没有DELAYED INSERT函数。”

可能是它不是INSERT本身会降低你的速度,但是你的MySQL实例总是忙于计算页面浏览量。一旦开始提供缓存的页面视图数据,这个问题就有可能消失。

答案 1 :(得分:1)

次要优化。你进行绑定的方式可以摆脱foreach语句并直接传递数组来执行。 PDO会将数组键映射到您在prepare语句中创建的绑定名称。

$sth->execute($data);

那就是说,你应该看看mysql中的慢查询日志,看看发生了什么。即使您使用的是Innodb,也有一些场景会让Innodb锁定桌子。这可能就是为什么插件有时需要很长时间。您可以将慢查询阈值减少到3秒以捕获查询。日志将告诉您每个阶段花费了多少时间(即锁定)。

答案 2 :(得分:0)

正如deceze所说,它可能需要更多细节。但我想它可能会陷入“Config :: getValue('site','url')”。顺便说一句,你的mysql是远程的吗?

答案 3 :(得分:-3)

您是否有理由使用prepare而不是仅仅致电pdo -> exec()

搜索周围显示许多人将基准标记prepare标记为比使用exec()慢得多且密集程度更高,尤其是当您不期待任何值时(另请参阅{{3}的文档) - 它注意到被设计为优化多次调用相同的查询。)

不是绑定你的值,你可以做这样的事情 -

function insert($table, $data) {
    ksort($data);

    $fieldNames = implode("`, `", array_keys($data));
    $fieldValues = implode("', '", array_values($data));

    $this->exec("INSERT INTO $table (`{$fieldNames}`) VALUES ('{$fieldValues}')");
}