ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

PHP-使用预准备语句没有速度优势?

2019-12-01 15:25:50  阅读:311  来源: 互联网

标签:prepared-statement mysql php pdo


我听说如果多次执行查询,带有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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有