Запрос PDO против выполнения - PullRequest
125 голосов
/ 15 января 2011

Они оба делают одно и то же, только по-разному?

Есть ли разница, кроме использования prepare между

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

и

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

?

Ответы [ 3 ]

138 голосов
/ 15 января 2011

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 для повышения безопасности .

См. Также: Являются ли PDOподготовленных операторов, достаточных для предотвращения внедрения SQL?

44 голосов
/ 15 января 2011

Нет, они не одинаковы.Помимо экранирования на стороне клиента, которое он предоставляет, подготовленный оператор компилируется на стороне сервера один раз, а затем может передаваться различные параметры при каждом выполнении.Это означает, что вы можете сделать:

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

3 голосов
/ 07 октября 2016

Ответ Гилиана великолепен, но я просто хотел добавить, что иногда бывают редкие исключения из лучших практик, и вы можете протестировать свою среду в обоих случаях, чтобы увидеть, что будет работать лучше.

В одном случае я обнаружил, что query работал быстрее для моих целей, потому что я выполнял массовую передачу доверенных данных из коробки Ubuntu Linux с PHP7 с плохо поддерживаемым драйвером Microsoft ODBC для MS SQL Server .

Я пришел к этому вопросу, потому что у меня был длинный скрипт для ETL , который я пытался выжать из-за скорости.Мне показалось интуитивно понятным, что query может быть быстрее, чем prepare & execute, потому что он вызывает только одну функцию вместо двух.Операция привязки параметров обеспечивает превосходную защиту, но она может быть дорогостоящей и, возможно, ее можно избежать, если в этом нет необходимости.

Учитывая пару редких условий :

  1. ЕслиВы не можете повторно использовать подготовленный оператор, потому что он не поддерживается драйвером Microsoft ODBC .

  2. Если вы не беспокоитесь о дезинфекции ввода и допустимо простое экранирование,Это может быть связано с тем, что привязка определенных типов данных не поддерживается драйвером Microsoft ODBC .

  3. 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;
}

Я играл с несколькими различными пробными версиями и подсчетами в моем конкретноми на 20-30% быстрее получают результаты с query, чем prepare / execute

5.8128969669342 prepare
5.8688418865204 prepare
4.2948560714722 query
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

Я c любопытныйчтобы увидеть, как этот тест сравнивается в других средах, таких как MySQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...