【问题标题】:Why am I not seeing the massive performance difference that I expect to see between prepared and non-prepared queries? [closed]为什么我没有看到准备好的查询和未准备好的查询之间的巨大性能差异? [关闭]
【发布时间】:2016-12-20 19:27:25
【问题描述】:

我认为在逐一循环超过一千条记录时,我会看到使用 PDO 语句PDO 查询 之间存在明显的性能差异。

我为每一个循环做了一千次,以获得平均结果,它们反映的时间几乎相同(≈0.105 秒)。为什么?我会认为准备好的语句是最快的。

这是我用于测试目的的代码:

$iter = 1000;
$idAry = range(1,1000);
$sumResultAry = array();

// [TEST1]
$func1 = function($id,array &$sumResultAry){
    list($dbCon,$DB,$TP) = AClass::retrieve_database_properties_();
    $sql = "
        SELECT 
            t1.id,
            t1.look_key
        FROM {$DB}.{$TP}test t1 
        WHERE 
            t1.id={$id} 
    ";

    if(false!==($result=$dbCon->query($sql))){
        if(false!==($row=$result->fetch(PDO::FETCH_ASSOC))){
            $sumResultAry[] = $row['id'];
        }
    }
};

$wh = fopen('test','w');
if($wh){
    for($i=0;$i<$iter;++$i){
        $startTime = microtime(true);
        foreach($idAry as $id){
            $func1($id,$sumResultAry);
        }
        $endTime = number_format((microtime(true)-$startTime),4);
        fwrite($wh,$endTime . "\n");
    }

    fclose($wh);
}

$result = 0;

$rh = fopen('test','r');
if($rh){
    while(!feof($rh)){
        $line = trim(fgets($rh));
        if($line!==''){
            $result += floatval($line);
        }
    }

    fclose($rh);
}

echo '<pre>';
echo 'test query' . "\n\n";
echo 'time: ' . ($result/$iter) . ' seconds' . "\n\n";
echo '</pre>';
// [/TEST1]

// [TEST2]
$func2 = function($id,array &$sumResultAry){
    $key = 'test';
    $sqlStmt = null;
    if(null===($sqlStmt=AClass::return_sqlStatement_($key))){// retrieving statement if previously stored
        list($dbCon,$DB,$TP) = AClass::retrieve_database_properties_();
        $sql = "
            SELECT 
                t1.id,
                t1.look_key
            FROM {$DB}.{$TP}test t1 
            WHERE 
                t1.id=:id
        ";
        if(AClass::prepare_sqlStatement_($key,$sql)){// preparing and storing statement
            $sqlStmt = AClass::return_sqlStatement_($key);
        }
    }
    if(null!==$sqlStmt){
        if(false!==($sqlStmt->execute(array(':id'=>$id)))){
            if(false!==($row=$sqlStmt->fetch(PDO::FETCH_ASSOC))){
                $sumResultAry[] = $row['id'];
            }
        }
    }
};

$wh = fopen('test','w');
if($wh){
    for($i=0;$i<$iter;++$i){
        $startTime = microtime(true);
        foreach($idAry as $id){
            $func2($id,$sumResultAry);
        }
        $endTime = number_format((microtime(true)-$startTime),4);
        fwrite($wh,$endTime . "\n");
    }

    fclose($wh);
}

$result = 0;

$rh = fopen('test','r');
if($rh){
    while(!feof($rh)){
        $line = trim(fgets($rh));
        if($line!==''){
            $result += floatval($line);
        }
    }

    fclose($rh);
}

echo '<pre>';
echo 'test statement' . "\n\n";
echo 'time: ' . ($result/$iter) . ' seconds' . "\n\n";
echo '</pre>';
// [/TEST2]

感谢你们中的一些人,我现在明白我需要使用更复杂的查询进行测试,才能注意到两者之间的显着性能差异。

【问题讨论】:

  • 根据天空中的伟大手册。 “通过使用准备好的语句,应用程序避免了重复分析/编译/优化循环。” php.net/manual/en/pdo.prepared-statements.php 您的查询非常简单,因此分析/编译/优化周期的 1000 次迭代可以忽略不计。尝试更复杂的查询。 (添加依赖子查询等)
  • @brassxzero 哦,我明白了!因此,对于更复杂的查询,我会看到不同之处。我将进一步测试以验证这一点。我知道这些东西可能已经测试了一千次,但我只是添加了一个类来存储在我的项目中使用的准备好的语句,并且想看看我这样做是否是好的,所以我开始测试它。谢谢。
  • 这里有问题吗?
  • @bassxzero 我一直将运行分析/编译/优化周期的过程称为“确定执行计划”。在 mysql(假设 mysql 或 postgres)中,这是准确的正确语言吗?
  • 这完全不清楚。

标签: php pdo prepared-statement


【解决方案1】:

无论如何,我不确定您是否会看到“巨大”的性能差异,除非您运行了很多次迭代。

对于单次查询运行,创建预准备语句并使用一组参数提交它比静态查询(对于单个查询和一组参数)花费的时间稍长。稍微说一下,我们说的是毫秒或几分之一毫秒。

您从准备好的语句(如果您的数据库支持它们)中得到的是:

  • SQL 注入保护
  • 使用不同参数(如循环)多次运行相同查询时会加快速度,因为数据库只创建一个执行计划。通常,您需要运行相当多的执行才能看到任何明显的东西。

如果它是一个快速、索引良好的查询,它本身只需要几毫秒即可运行,并且要构建一个简单的执行计划,那么您可能需要运行数千个请求才能通过准备好的语句获得任何明显的改进。静态查询。

所以,只需使用准备好的语句,因为它总体上更好。

【讨论】:

  • @Ray 我知道这是单个请求的情况。但是多个请求呢?
  • @MarkBaker 查看我的更新
  • @4n0nym0u5 查看我的更新。对于在几次请求后对同一语句的重复请求,您应该会看到一些改进,而不是一次又一次地使用不同的值运行静态查询
  • @Ray 我知道您在答案中提供的事实,但我的简单测试并未反映这些事实,我想知道为什么......但是答案 bassxzero 给了我作为对我的问题的评论,现在我看到我需要提出一个更复杂的查询来注意两者之间的性能差异。我还是会接受你的回答,谢谢。
  • @4n0nym0u5 我在答案的底部添加了信息,这几乎反映了 bassxzero 在对您的 OP 的评论中指出的关于 mysql 构建执行计划所需的时间(分析/编译/优化循环构造执行计划)
【解决方案2】:

为什么我没有看到准备好的查询和未准备好的查询之间的巨大性能差异?

因为没有。

我不知道你从哪里得到这个想法,但是一个准备好的语句在任何地方都没有给你带来显着的性能差异,更不用说“巨大”的了。 即使使用得当

【讨论】:

  • 所以...只是想知道您的想法...尽可能使用准备好的语句是一种好习惯吗?如果通过不同的类和方法重用它们是否应该存储?谢谢
  • 一个好问题。我认为收益不值得麻烦。它会使您的代码变得更加复杂,几乎没有收益。此外,在 PHP 中重用准备好的语句的机会很小。
  • 顺便说一下,我将彻底阅读您的 PDO 教程。 PDO 的使用对我来说还是有点新意,习惯了 mysqli,但我更喜欢 PDO 作为它们的占位符。
  • 很高兴为您提供帮助。如果您碰巧有任何问题,请随时询问
猜你喜欢
  • 2012-03-30
  • 1970-01-01
  • 2012-05-16
  • 2013-12-25
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 2011-03-25
  • 1970-01-01
相关资源
最近更新 更多