둘 다 똑같은 일을합니까?
prepare
사이를 사용하는 것 외에 다른 점이 있습니까?
$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();
과
$sth = $db->prepare("SELECT * FROM table");
$sth->execute();
$result = $sth->fetchAll();
?
답변
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
보안 강화 를 고수하는 것 입니다.
답변
아니요, 동일하지 않습니다. 제공되는 클라이언트 측에서 이스케이프 처리하는 것 외에도 준비된 명령문은 서버 측에서 한 번 컴파일 된 다음 각 실행시 다른 매개 변수 를 전달할 수 있습니다 . 당신이 할 수있는 것을 의미 :
$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의 답변 은 훌륭하지만 때로는 모범 사례에 드문 예외가 있음을 추가하고 싶었습니다. 환경을 두 가지 방법으로 테스트하여 무엇이 가장 효과가 좋은지 확인할 수 있습니다.
한 가지 경우, 나는 MS SQL Server 용으로query
제대로 지원되지 않는 Microsoft ODBC 드라이버를 사용하여 PHP7을 실행하는 Ubuntu Linux 상자에서 신뢰할 수있는 데이터를 대량 전송하기 때문에 내 목적에 더 빨리 작동 한다는 것을 알았습니다 .
나는 속도를 위해 짜려고했던 ETL에 대한 스크립트를 오래 실행했기 때문에이 질문에 도달했습니다 . & query
보다 빠를 수있는 것은 직관적 이었습니다. 두 개가 아닌 하나의 함수 만 호출했기 때문입니다. 매개 변수 바인딩 조작은 탁월한 보호 기능을 제공하지만 비용이 많이 들고 불필요한 경우 피할 수 있습니다.prepare
execute
몇 가지 드문 조건이 주어지면 :
-
당신이 준비된 문을 다시 사용할 수없는 경우 때문에 그것은 마이크로 소프트 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
보다 20-30 % 빠른 결과를 일관되게 얻었 습니다.prepare
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 준비
7.3791449069977 준비를
6.0673267160143 (7) 평균 조제
(8) 쿼리 평균 : 4.3276024162769
이 테스트가 MySQL과 같은 다른 환경에서 어떻게 비교되는지 궁금합니다.