PDO的查询与执行

时间:2011-01-15 16:12:22

标签: php pdo

他们都做同样的事情,只是区别对待吗?

除了在

之间使用prepare之外是否有任何区别
$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();

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

3 个答案:

答案 0 :(得分:137)

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以提高安全性

另请参阅:Are PDO prepared statements sufficient to prevent SQL injection?

答案 1 :(得分:44)

不,他们不一样。除了它提供的客户端转义之外,在服务器端编译一个准备好的语句,然后在每次执行时都可以传递不同的参数。这意味着你可以做到:

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

它们通常会为您提供性能提升,但在小范围内并不明显。 Read more on prepared statements (MySQL version)

答案 2 :(得分:3)

Gilean's answer很棒,但我只想补充一点,有时最佳做法很少有例外,您可能希望以两种方式测试您的环境,看看什么效果最好。

在一个案例中,我发现query为我的目的工作得更快,因为我从运行PHP7的Ubuntu Linux机箱批量传输受信任数据,支持不足Microsoft ODBC driver for MS SQL Server

我到达了这个问题,因为我有一个ETL长期运行的脚本,我试图挤压速度。对我来说,query可能比prepareexecute更快,这似乎很直观。 CREATE TABLE performancetest ( sid INT IDENTITY PRIMARY KEY, id INT, val VARCHAR(100) ); 因为它只调用了一个函数而不是两个函数。参数绑定操作提供了极好的保护,但它可能很昂贵,如果不必要,可能会避免。

鉴于一些罕见的情况

  1. 如果您不能重复使用预先准备好的陈述,因为it's not supported by the Microsoft ODBC driver

  2. 如果您不担心消毒输入,可以接受简单的转义。可能是这种情况,因为binding certain datatypes isn't supported by the Microsoft ODBC driver

  3. Microsoft ODBC驱动程序不支持
  4. PDO::lastInsertId

  5. 这是我用来测试我的环境的方法,希望你可以在你的环境中复制它或更好的东西:

    首先,我在Microsoft SQL Server中创建了一个基本表

    $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 / td

    的结果快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。