Запрос вставки PDO замедляет работу сайта - PullRequest
4 голосов
/ 27 марта 2012

На моем сайте я закодировал функцию, которая показывает, сколько уникальных посетителей и сколько просмотров страниц я получаю в день.

Проблема в том, что иногда запрос на вставку выполняется вечно, а в InnoDB нет DELAYED INSERT function.

Редактировать: Это использует 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 ]

1 голос
/ 06 декабря 2012

Незначительная оптимизация. При выполнении привязки вы можете избавиться от оператора foreach и напрямую передать массив для выполнения. PDO сопоставит ключ массивов с именами: привязки, которые вы создали в операторе prepare.

$sth->execute($data);

Тем не менее, вы должны посмотреть на свой медленный журнал запросов в MySQL, чтобы увидеть, что происходит. Даже если вы используете Innodb, есть сценарии, в которых Innodb блокирует стол. Вот почему иногда вставки занимают много времени. Вы можете уменьшить порог медленного запроса до 3 секунд для захвата запросов. В журнале будет указано, сколько времени было потрачено на каждом этапе (т. Е. Заблокировано).

1 голос
/ 03 июля 2012

«На моем сайте я закодировал функцию, которая показывает, сколько уникальных посетителей и сколько просмотров страниц я получаю в день».

Вы выполняете живой запрос для каждого запроса страницы? Это вполне может быть проблемой производительности. Это никого не убьет, если вы будете запрашивать эти цифры каждый час или около того и кэшировать значение. Последующие просмотры страниц могут затем использовать кэшированное значение вместо реального.

"Проблема в том, что иногда запрос вставки выполняется вечно, а в InnoDB нет функции DELAYED INSERT."

Возможно, что не сам INSERT замедляет вас, а что ваш экземпляр MySQL просто занят все время вычислением просмотров страниц. Существует вероятность того, что эта проблема исчезнет, ​​как только вы начнете обслуживать кэшированные цифры просмотра страниц.

0 голосов
/ 06 декабря 2012

Есть ли причина, по которой вы используете prepare вместо того, чтобы просто звонить pdo -> exec()?

Поиск вокруг показывает, что многие люди отмечают prepare как гораздо медленнее и интенсивнее, чем exec() особенно если вы не ожидаете каких-либо значений назад (см. также документ для Prepare - он отмечает, что он предназначен для оптимизации вызова одного и того же запроса несколько раз).

Вместо привязки ваших значенийВы могли бы сделать что-то вроде этого -

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

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

    $this->exec("INSERT INTO $table (`{$fieldNames}`) VALUES ('{$fieldValues}')");
}
0 голосов
/ 03 июля 2012

Как сказала децезе, может потребоваться больше деталей.Но я предполагаю, что он может застрять в "Config :: getValue ('site', 'url')".Кстати, ваш mysql удаленный?

...