Jawaban:
query
menjalankan pernyataan SQL standar dan mengharuskan Anda untuk melarikan diri semua data dengan benar untuk menghindari Suntikan SQL dan masalah lainnya.
execute
menjalankan pernyataan yang disiapkan yang memungkinkan Anda untuk mengikat parameter untuk menghindari keharusan untuk melarikan diri atau mengutip parameter. execute
juga akan berkinerja lebih baik jika Anda mengulangi permintaan beberapa kali. Contoh pernyataan yang disiapkan:
$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
Praktik terbaik adalah tetap dengan pernyataan yang disiapkan dan execute
untuk meningkatkan keamanan .
Lihat juga: Apakah pernyataan yang disiapkan PDO cukup untuk mencegah injeksi SQL?
: calories
apakah itu setara dengan mysql_real_escape_string()
untuk menghentikan suntikan atau apakah Anda memerlukan lebih dari sekedar $sth->bindParam(':calories', $calories);
untuk meningkatkan keamanan?
query
mengembalikan PDOStatement , bukannya bool like execute
?
Tidak, mereka tidak sama. Selain melarikan diri pada sisi klien yang disediakannya, pernyataan yang sudah disiapkan dikompilasi di sisi server sekali, dan kemudian dapat melewati parameter yang berbeda pada setiap eksekusi. Yang berarti Anda dapat melakukan:
$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);
Mereka umumnya akan memberi Anda peningkatan kinerja, meskipun tidak terlihat dalam skala kecil. Baca lebih lanjut tentang pernyataan yang disiapkan (versi MySQL) .
Jawaban Gilean sangat bagus, tetapi saya hanya ingin menambahkan bahwa kadang-kadang ada pengecualian langka untuk praktik terbaik, dan Anda mungkin ingin menguji lingkungan Anda dengan dua cara untuk melihat apa yang akan bekerja paling baik.
Dalam satu kasus, saya menemukan bahwa itu query
bekerja lebih cepat untuk tujuan saya karena saya secara massal mentransfer data tepercaya dari kotak Linux Ubuntu yang menjalankan PHP7 dengan driver ODBC Microsoft yang tidak didukung untuk MS SQL Server .
Saya sampai pada pertanyaan ini karena saya memiliki skrip berjalan lama untuk ETL yang saya coba peras untuk kecepatan. Tampaknya intuitif bagi saya yang query
bisa lebih cepat daripada prepare
& execute
karena itu hanya memanggil satu fungsi, bukan dua. Operasi pengikatan parameter memberikan perlindungan yang sangat baik, tetapi mungkin mahal dan mungkin dihindari jika tidak perlu.
Diberikan beberapa kondisi langka :
Jika Anda tidak dapat menggunakan kembali pernyataan yang disiapkan karena tidak didukung oleh driver Microsoft ODBC .
Jika Anda tidak khawatir tentang sanitasi input dan pelolosan sederhana dapat diterima. Ini mungkin terjadi karena mengikat tipe data tertentu tidak didukung oleh driver Microsoft ODBC .
PDO::lastInsertId
tidak didukung oleh driver Microsoft ODBC.
Inilah metode yang saya gunakan untuk menguji lingkungan saya, dan mudah-mudahan Anda dapat meniru atau sesuatu yang lebih baik di lingkungan Anda:
Untuk memulai, saya telah membuat tabel dasar di Microsoft SQL Server
CREATE TABLE performancetest (
sid INT IDENTITY PRIMARY KEY,
id INT,
val VARCHAR(100)
);
Dan sekarang tes dasar waktunya untuk metrik kinerja.
$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;
}
Saya telah bermain dengan beberapa percobaan dan hitungan berbeda di lingkungan spesifik saya, dan secara konsisten mendapatkan antara 20-30% hasil lebih cepat dengan query
daripada prepare
/execute
5,8128969669342 mempersiapkan
5,8688418865204 mempersiapkan
4,2948560714722 permintaan
4,9533629417419 permintaan
5,9051351547241 mempersiapkan
4,332102060318 permintaan
5,9672858715057 mempersiapkan
5,0667371749878 permintaan
3,8260300159454 permintaan
4,0791549682617 permintaan
4,3775160312653 permintaan
3,6910600662231 permintaan
5,2708210945129 mempersiapkan
6,2671611309052 mempersiapkan
7,3791449069977 mempersiapkan
(7) mempersiapkan rata-rata: 6,0673267160143
(8) permintaan rata-rata: 4,3276024162769
Saya ingin tahu bagaimana perbandingan tes ini di lingkungan lain, seperti MySQL.