PHP-使用预准备语句没有速度优势?
作者:互联网
我听说如果多次执行查询,带有MySQL数据库的“ Prepared Statements”可以提高速度,并且我认为我在项目中有一个理想的案例.但是我运行了一些基准测试,却发现完全相反.我使用这些语句是错误的(对于准备好的语句来说不是理想的情况),还是它们不如我想象的那么快?
情况是锦标赛结果网格.有多个学校参加了多个活动,每个学校都有每个活动的分数.为了获得所有学校在所有事件中的分数,需要使用带有LEFT JOIN的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;
我编写了两个PHP测试脚本,以使用本地PDO对象(prepare()/ bindValue()/ execute()与query())针对示例数据(200个事件)运行:
编辑修改后的测试具有以下建议(原始查询需要获取,获取不同的ID并在循环外绑定准备).现在仅对准备好的语句提供适度的速度优势:
准备的声明:
$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秒).我做错了吗?或者说即使在重复的情况下,Prepared Statements也不会更快,这是准确的吗?
编辑更新的测试现在可以准备33.95秒,而普通版本则为34.10. Huzzah,准备好的语句更快.但仅需不到一秒的时间即可重复10,000次.可能是因为我的查询不是那么复杂(准备好的语句出于其优势而缓存了语法分析树)?还是在这里还有更多优化要做?
解决方法:
看来您可能没有将苹果与苹果进行比较.
PDO::query()
执行一条SQL语句,将结果集作为PDOStatement对象返回.
要获得实际结果,您需要遍历返回的对象,或者与准备好的语句一样,调用fetchAll()将整个结果集加载到数组中
正确的原始查询循环可能应该是:
for ($i=0; $i<$max; $i++) {
$stmt = $db->query($sql);
$rs = $stmt->fetchAll();
}
或者从准备好的语句循环中删除fetchAll()调用.
您还可以通过使用bindParam()而不是bindValue()减少准备好的语句所需的方法调用.
$school_id = null;
$stmt->bindParam(':school_id', $school_id);
for ($i=0; $i<$max; $i++) {
$school_id = 10;
$stmt->execute();
$rs = $stmt->fetchAll();
}
标签:prepared-statement,mysql,php,pdo 来源: https://codeday.me/bug/20191201/2081825.html