Я слышал, что подготовленные операторы с базой данных MySQL могут предложить увеличение скорости, если запрос выполняется несколько раз, и я подумал, что у меня есть идеальный случай для этого в проекте.Но я провел несколько тестов и обнаружил, что все наоборот.Я неправильно использую эти заявления (не идеальная ситуация для подготовленных заявлений), или они просто не так быстры, как я думал?
Ситуация - это таблица результатов турнира.Есть несколько школ, участвующих в нескольких мероприятиях, и каждая школа имеет оценку для каждого события.Чтобы получить оценки отдельных школ по всем событиям, требуется SQL-запрос с LEFT JOIN, например:
SELECT e.`id`, e.`name`, c.`competing`, c.`raw`, c.`final` FROM `events` e LEFT JOIN `scores` c ON e.`id`=c.`event_id` WHERE c.`school_id`=:school_id;
. Я написал два сценария PHP-теста для запуска с образцами данных (200 событий), используянативные объекты PDO (prepare()
/ bindValue()
/ execute()
против query()
):
EDIT Модифицированные тесты с предложениями, приведенными ниже (для запроса ванили требуется выборка, выборка различных идентификаторов,и связать готовить вне цикла).Только дает скромное преимущество в скорости готовым операторам сейчас:
Готовое заявление:
$start = microtime(true);
$sql = 'SELECT e.`id`, e.`name`, c.`competing`, c.`raw`, c.`final` FROM `events` e LEFT JOIN `scores` c ON e.`id`=c.`event_id` WHERE c.`school_id`=:school_id';
echo $sql."<br />\n";
$stmt = $db->prepare($sql);
$sid = 0;
$stmt->bindParam(':school_id', $sid);
for ($i=0; $i<$max; $i++) {
$sid = rand(1,499);
$stmt->execute();
$rs = $stmt->fetchAll();
}
$delta = bcsub(microtime(true), $start, 4);
echo "<strong>Overall time:</strong> $delta<br />\n";
echo "<strong>Average time:</strong> ".($delta/$max)."<br />\n";
Ванильный запрос:
set_time_limit(15); // Add time for each run
$start = microtime(true);
$sql = 'SELECT e.`id`, e.`name`, c.`competing`, c.`raw`, c.`final` FROM `events` e LEFT JOIN `scores` c ON e.`id`=c.`event_id` WHERE c.`school_id`={$sid}';
echo $sql."<br />\n";
for ($i=0; $i<$max; $i++) {
$sid = rand(1,499);
$stmt = $db->query("SELECT e.`id`, e.`name`, c.`competing`, c.`raw`, c.`final` FROM `events` e LEFT JOIN `scores` c ON e.`id`=c.`event_id` WHERE c.`school_id`={$sid}");
$rs = $stmt->fetchAll();
}
$delta = bcsub(microtime(true), $start, 4);
echo "<strong>Overall time:</strong> $delta<br />\n";
echo "<strong>Average time:</strong> ".($delta/$max)."<br />\n";
Я снова и снова получаю оценки событий в одной и той же школе (ID школы № 10) и, установив $max
на 10 000, я получаю результаты, которые показывают, что ванильные запросы выполняются на 30% быстрее (25,72 секунды против 36,79).Я делаю это неправильно, или это точно, что подготовленные операторы не быстрее даже в повторяющейся ситуации?
EDIT обновленные тесты теперь получают 33,95 секунды против 34,10 ванили.Huzzah, подготовленные заявления быстрее.Но только на долю секунды за 10 000 итераций.Возможно, потому что мой запрос не настолько сложен (подготовленные операторы кэшируют дерево разбора для их преимущества)?Или здесь еще есть что оптимизировать?