Gilean's answer 很棒,但我只是想补充一点,有时最佳实践存在极少数例外情况,您可能希望以两种方式测试您的环境,看看哪种方式最有效。
在一种情况下,我发现query 对我的目的来说工作得更快,因为我正在从一个运行 PHP7 的 Ubuntu Linux 机器上批量传输受信任的数据,而 Microsoft ODBC driver for MS SQL Server 的支持很差。
我遇到了这个问题,因为我有一个运行很长时间的 ETL 脚本,我正试图加快速度。在我看来,query 可能比prepare 和execute 更快,因为它只调用一个函数而不是两个函数,这似乎很直观。参数绑定操作提供了很好的保护,但它可能会很昂贵,如果不必要的话可以避免。
考虑到一些罕见的情况:
如果您因为it's not supported by the Microsoft ODBC driver而无法重用准备好的语句。
如果您不担心清理输入并且可以接受简单的转义。这可能是因为binding certain datatypes isn't supported by the Microsoft ODBC driver。
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/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 等其他环境中的对比情况。