Câu trả lời:
query
chạy một câu lệnh SQL tiêu chuẩn và yêu cầu bạn thoát đúng tất cả dữ liệu để tránh Tiêm SQL và các vấn đề khác.
execute
chạy một câu lệnh được chuẩn bị cho phép bạn liên kết các tham số để tránh phải thoát hoặc trích dẫn các tham số. execute
cũng sẽ hoạt động tốt hơn nếu bạn lặp lại một truy vấn nhiều lần. Ví dụ về các tuyên bố đã chuẩn bị:
$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
Thực hành tốt nhất là gắn bó với các tuyên bố đã chuẩn bị và execute
để tăng tính bảo mật .
Xem thêm: Các tuyên bố chuẩn bị PDO có đủ để ngăn chặn việc tiêm SQL không?
: calories
đó là loại tương đương mysql_real_escape_string()
để ngừng tiêm hoặc bạn cần nhiều hơn là chỉ $sth->bindParam(':calories', $calories);
để tăng cường an ninh?
query
trả về PDOStatement , thay vì bool như thế execute
nào?
Không, chúng không giống nhau. Ngoài việc thoát ra ở phía máy khách mà nó cung cấp, một câu lệnh được chuẩn bị được biên dịch ở phía máy chủ một lần, và sau đó có thể được truyền các tham số khác nhau ở mỗi lần thực hiện. Điều đó có nghĩa là bạn có thể làm:
$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);
Họ thường sẽ cung cấp cho bạn một cải tiến hiệu suất, mặc dù không đáng chú ý trên quy mô nhỏ. Đọc thêm về các tuyên bố đã chuẩn bị (phiên bản MySQL) .
Câu trả lời của Gilean rất hay, nhưng tôi chỉ muốn nói thêm rằng đôi khi có những trường hợp ngoại lệ hiếm hoi đối với các thực tiễn tốt nhất và bạn có thể muốn kiểm tra môi trường của mình theo cả hai cách để xem cái gì sẽ hoạt động tốt nhất.
Trong một trường hợp, tôi thấy rằng nó query
hoạt động nhanh hơn cho mục đích của mình vì tôi đã chuyển số lượng lớn dữ liệu đáng tin cậy từ hộp Ubuntu Linux chạy PHP7 với trình điều khiển Microsoft ODBC được hỗ trợ kém cho MS SQL Server .
Tôi đã đến câu hỏi này bởi vì tôi có một kịch bản chạy dài cho một ETL mà tôi đang cố gắng để đạt được tốc độ. Nó dường như trực quan với tôi query
có thể nhanh hơn prepare
& execute
bởi vì nó chỉ gọi một chức năng thay vì hai chức năng. Hoạt động liên kết tham số cung cấp bảo vệ tuyệt vời, nhưng nó có thể tốn kém và có thể tránh được nếu không cần thiết.
Đưa ra một vài điều kiện hiếm gặp :
Nếu bạn không thể sử dụng lại câu lệnh đã chuẩn bị vì nó không được trình điều khiển Microsoft ODBC hỗ trợ .
Nếu bạn không lo lắng về việc vệ sinh đầu vào và thoát đơn giản thì có thể chấp nhận được. Đây có thể là trường hợp vì ràng buộc một số kiểu dữ liệu nhất định không được trình điều khiển Microsoft ODBC hỗ trợ .
PDO::lastInsertId
không được trình điều khiển Microsoft ODBC hỗ trợ.
Đây là một phương pháp tôi đã sử dụng để kiểm tra môi trường của mình và hy vọng bạn có thể sao chép nó hoặc một cái gì đó tốt hơn trong môi trường của bạn:
Để bắt đầu, tôi đã tạo một bảng cơ bản trong Microsoft SQL Server
CREATE TABLE performancetest (
sid INT IDENTITY PRIMARY KEY,
id INT,
val VARCHAR(100)
);
Và bây giờ là một bài kiểm tra thời gian cơ bản cho các số liệu hiệu suất.
$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;
}
Tôi đã chơi với nhiều thử nghiệm và số lượng khác nhau trong môi trường cụ thể của tôi, và liên tục nhận được từ 20-30% nhanh hơn kết quả với query
hơn prepare
/execute
5,8128969669342 chuẩn bị
5,8688418865204 chuẩn bị
4,2948560714722 truy vấn
4,9533629417419 truy vấn
5,9051351547241 chuẩn bị
4,332102060318 truy vấn
5,9672858715057 chuẩn bị
5,0667371749878 truy vấn
3,8260300159454 truy vấn
4,0791549682617 truy vấn
4,3775160312653 truy vấn
3,6910600662231 truy vấn
5,2708210945129 chuẩn bị
6,2671611309052 chuẩn bị
7,3791449069977 chuẩn bị
(7) chuẩn bị trung bình: 6,0673267160143
(8) truy vấn trung bình: 4,3276024162769
Tôi tò mò muốn xem thử nghiệm này so sánh như thế nào trong các môi trường khác, như MySQL.