Answers:
query
运行标准SQL语句,并要求您正确转义所有数据,以避免SQL注入和其他问题。
execute
运行一个准备好的语句,该语句使您可以绑定参数以避免转义或引用参数。execute
如果您多次重复查询,效果也会更好。准备的语句示例:
$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories);
$sth->bindParam(':colour', $colour);
$sth->execute();
// $calories or $color do not need to be escaped or quoted since the
// data is separated from the query
最佳实践是坚持准备好的语句并execute
提高安全性。
: calories
,那么相当于mysql_real_escape_string()
停止注射还是您需要做更多的事情$sth->bindParam(':calories', $calories);
来增强安全性?
query
返回PDOStatement而不是bool之类的execute
?
不,他们不一样。除了在客户端提供转义功能外,准备好的语句在服务器端还会被编译一次,然后可以在每次执行时传递不同的参数。这意味着您可以:
$sth = $db->prepare("SELECT * FROM table WHERE foo = ?");
$sth->execute(array(1));
$results = $sth->fetchAll(PDO::FETCH_ASSOC);
$sth->execute(array(2));
$results = $sth->fetchAll(PDO::FETCH_ASSOC);
尽管在小范围内并不引人注目,但它们通常可以使您提高性能。阅读更多有关准备好的语句(MySQL版本)的信息。
Gilean的回答很好,但我只是想补充一点,有时最佳实践很少有例外,您可能想两种方法都测试一下您的环境,以了解最有效的方法。
在一个案例中,我发现它可以query
更快地实现我的目的,因为我是从运行PHP7的Ubuntu Linux盒中,通过对MS SQL Server的Microsoft ODBC驱动程序支持不佳,批量传输受信任的数据。
我遇到了这个问题,因为我的ETL脚本运行时间很长,因此我试图提高速度。在我看来,这query
可能比prepare
&更快,execute
因为它只调用一个函数而不是两个。参数绑定操作提供了出色的保护,但是它可能很昂贵,并且在不必要的情况下可以避免。
考虑到几个罕见的情况:
如果由于Microsoft ODBC驱动程序不支持已准备好的语句而无法重用它。
如果您不担心清理输入,可以进行简单的转义。可能是因为Microsoft ODBC驱动程序不支持绑定某些数据类型。
PDO::lastInsertId
不被Microsoft ODBC驱动程序支持。
这是我用来测试环境的一种方法,希望您可以复制它或在您的环境中更好的东西:
首先,我在Microsoft SQL Server中创建了一个基本表
CREATE TABLE performancetest (
sid INT IDENTITY PRIMARY KEY,
id INT,
val VARCHAR(100)
);
现在是性能指标的基本定时测试。
$logs = [];
$test = function (String $type, Int $count = 3000) use ($pdo, &$logs) {
$start = microtime(true);
$i = 0;
while ($i < $count) {
$sql = "INSERT INTO performancetest (id, val) OUTPUT INSERTED.sid VALUES ($i,'value $i')";
if ($type === 'query') {
$smt = $pdo->query($sql);
} else {
$smt = $pdo->prepare($sql);
$smt ->execute();
}
$sid = $smt->fetch(PDO::FETCH_ASSOC)['sid'];
$i++;
}
$total = (microtime(true) - $start);
$logs[$type] []= $total;
echo "$total $type\n";
};
$trials = 15;
$i = 0;
while ($i < $trials) {
if (random_int(0,1) === 0) {
$test('query');
} else {
$test('prepare');
}
$i++;
}
foreach ($logs as $type => $log) {
$total = 0;
foreach ($log as $record) {
$total += $record;
}
$count = count($log);
echo "($count) $type Average: ".$total/$count.PHP_EOL;
}
我在自己的特定环境中进行了多次不同的试验和计数,结果始终query
比prepare
/ 快20-30%execute
5.8128969669342准备
5.8688418865204准备
4.2948560714722查询
4.9533629417419查询
5.9051351547241准备
4.332102060318查询
5.9672858715057准备
5.0667371749878查询
3.8260300159454查询
4.0791549682617查询
4.3775160312653查询
3.6910600662231查询
5.2708210945129准备
6.2671611309052准备
6.0
(7.3791449069977)准备(7.3791449069769)
(平均)7.792449069977 (准备平均)(7.9791449069977)(平均)7.791449069977 (准备)7.3791449069977 (平均)7.691449069977 (准备)7.3791449069977 (平均)7.691449069977 (准备)7.3791449069977 (平均)
我很好奇该测试在其他环境(例如MySQL)中如何进行比较。