On my site I have coded a function that shows you how many unique visitors and how many pageviews I get per day.
The problem is that sometimes the insert query takes forever and in InnoDB theres no DELAYED INSERT function.
Edit: It is using InnoDB, what I mean with long loading time is around 6 seconds instead of like 0.1-0.5 seconds. As soon as I remove the logging the site is much faster.
The $b array bellow contains browser info, but according to XHProf its the PDO query that’s taking so long to execute.
The insert code is this:
$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);
and the insert function code:
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();
}
A minor optimization. The way you are doing your binding you can get rid of the foreach statement and pass the array directly to execute. PDO will map the arrays key to the :binding names you created in the prepare statement.
That said, you should look at your slow query log in mysql to see what is going on. Even though you are using Innodb, there are scenarios where Innodb will lock the table. That could be why inserts are taking a long time sometimes. You can reduce your slow query threshold to something like 3 seconds to capture the queries. The log will tell you how much time was spent in each stage (i.e. locked).