PDO 的查询与执行

他们做的是同一件事,只是不同而已?

除了使用 prepare之外

$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();

还有

$sth = $db->prepare("SELECT * FROM table");
$sth->execute();
$result = $sth->fetchAll();

147579 次浏览

query 运行没有参数化数据的标准 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,以增强安全性。

参见: PDO 准备的语句是否足以防止 SQL 注入?

不,他们不一样。除了它在客户端提供的转义之外,每次执行时 准备好的语句在服务器端编译一次,然后可以传递不同的参数。这意味着你可以做:

$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);

它们通常会给你带来性能上的提高,尽管在小范围内并不明显。

Gilean 的回答 很棒,但是我只想补充一点,有时候最佳实践中会有一些罕见的例外情况,您可能希望通过两种方式测试您的环境,看看哪种方式最有效。

在一个案例中,我发现 query的工作速度更快,因为我正在批量传输来自运行 PHP7的 Ubuntu Linux 机器的可信数据,而 用于 MSSQLServer 的 MicrosoftODBC 驱动程序的支持很差。

我来到这个问题,因为我有一个很长的运行脚本的 ETL,我试图挤压速度。对我来说,query可能比 prepareexecute更快,这似乎是直观的,因为它只调用一个函数而不是两个。参数绑定操作提供了极好的保护,但是如果没有必要的话,这种操作可能代价高昂并且可能避免。

考虑到一些罕见的条件 :

  1. 如果因为 它不受 MicrosoftODBC 驱动程序的支持而无法重用准备好的语句。

  2. 如果您不担心消毒输入和简单的转义是可以接受的。

  3. MicrosoftODBC 驱动程序不支持 PDO::lastInsertId

下面是我用来测试我的环境的一个方法,希望你可以在你的环境中复制它或者更好的东西:

首先,我用 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/execute快20-30%

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
7.3791449069977准备
(7)准备平均: 6.0673267160143
(8)查询平均值: 4.3276024162769

我很想知道这个测试在其他环境(如 MySQL)中是如何进行比较的。