php - 使用占位符时 PDO 执行速度较慢

标签 php mysql pdo

我正在制作一些返回计数和分组结果的 JSON 端点。对于此端点,我使用 PDO 和命名占位符。使用命名占位符时,PHP 响应在执行阶段最多需要六秒。当执行相同的查询并将值直接放入查询中时,响应几乎是即时的。

我正在更新仍使用 mysql_query() 的旧代码以使用 PDO 语句。

    <?php
    header("Access-Control-Allow-Origin: *");
    header("Content-Type: application/json; charset=UTF-8");
    header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
    $conn = new PDO('mysql:host=localhost;dbname=nameOfDB', 'username', 'password');
    $conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conn->exec("set names utf8");

    $query_slow = "SELECT t.meta as meta, count(*) as cnt 
    FROM field, repo, t, uplink, link  
    WHERE (
        repo.rp1 = field.id OR 
        repo.rp2 = field.id OR 
        repo.rp3 = field.id OR 
        repo.rp4 = field.id)
    AND repo.combination = t.meta 
    AND t.doc_id = uplink.doc_id 
    AND uplink.written = 1 
    AND uplink.link_id = link.id 
    AND field.id = :field 
    AND t.earliest > :min 
    AND t.latest < :max 
    GROUP BY t.meta 
    ORDER BY cnt desc";

    if($parameters){
        $stmt = $conn->prepare($query_slow);
        $stmt->execute($parameters);
        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        echo json_encode($data, JSON_UNESCAPED_UNICODE );
    }

如果我执行var_dump($parameters),我会得到以下返回值:

    $parameters = array(3) {
      [":field"]=>
      int(5)
      [":min"]=>
      int(-1000)
      [":max"]=>
      int(600)
    }

这是快速查询:

    $query_fast = "SELECT t.meta as meta, count(*) as cnt 
    FROM field, repo, t, uplink, link  
    WHERE (
        repo.rp1 = field.id OR 
        repo.rp2 = field.id OR 
        repo.rp3 = field.id OR 
        repo.rp4 = field.id)
    AND repo.combination = t.meta 
    AND t.doc_id = uplink.doc_id 
    AND uplink.written = 1 
    AND uplink.link_id = link.id 
    AND field.id=5 
    and t.earliest > -1000 
    and t.latest <600  
    GROUP BY t.meta 
    ORDER BY cnt desc";

    if(1==1){
    // I ditched the $parameters, so my execute is empty.
    $stmt = $conn->prepare($query_slow);
    $stmt->execute();
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo json_encode($data, JSON_UNESCAPED_UNICODE );
    }


slow_query 运行最多可能需要 6 秒。如果我使用填充的值和空的 execute() 运行相同的查询,我的响应几乎会立即出现。我对 PDO 做错了什么?

当给execute()一个数组时,我的页面响应速度很慢。当使用没有参数的查询时。响应是即时的。

我的计时代码按照@RiggsFolly的要求:

所以我在那里运行了计时代码:

    if($parameters){
    $time_prepare = microtime(true);
    $stmt = $conn->prepare($querygraph);
    $time_pre_exec = microtime(true);
    $stmt->execute(($parameters));
    //$stmt->execute();
    $time_post_exec = microtime(true);
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $time_post_fetch = microtime(true);
    echo json_encode($data, JSON_UNESCAPED_UNICODE );
    }

这是使用参数 5、-800 和 800(与之前使用的相同)。我的计时代码显示:

start:          1563972660.9188      (First line of the script)
prepare:        1563972660.9197        ==$time_prepare
pre execution:  1563972660.9201  ==$time_pre_exec
post execution: 1563972669.0058  ==$time_post_exec ==> 9 seconds!
post fetch:     1563972669.0058 

当在不带占位符的查询上使用相同的参数时,我使用相同的查询和空的execute()。我将占位符替换为我在准备好的语句中使用的相同值。时间看起来像:

prepare:        1563973120.2965
pre execution:  1563973120.2969      //before execution()
post execution: 1563973120.312      //after executeion()
post fetch:     1563973120.3121

最佳答案

对于有类似问题的人;根据 @YourCommonSense 的建议修复了该问题。

我必须明确使用bindValue();现在整个执行(从开始到结束)大约需要 0.02 秒,这比我希望的要好得多。对于动态生成的查询,我将代码更改为:

$conditions = [];           //values to be inserted by type on placeholder
$parameters = [];           //kind of thing to execute in the query with the placeholder (substring of a query with a named placeholder)
$bindTypes=[];              //the type expected to be for a placeholder (the function takes this as third argument. It should be a long type (strings give errors, hence the if/else if block))
$placeholders=[];           //contains only the :placeholders. Use this to tell the bindvalue() function that you want to bind a value X to placeholder :X 

if(isset($_GET["min"])){
    $mindate = (int)$_GET["min"];
    if($mindate != ""){
        $conditions[] = 't.earliest>= :mindate';
        $parameters[] = $mindate;
        $bindTypes[] = 'int';
        $placeholders[] = ':mindate';
    }
}
if(isset($_GET["max"])){
    $maxdate= (int)$_GET["max"];
    if($maxdate!= ""){
        $conditions[] = 't.latest>= :maxdate';
        $parameters[] = $maxdate;
        $bindTypes[] = 'int';
        $placeholders[] = ':maxdate';
    }
}

if($parameters){
    $stmt = $conn->prepare($querygraph);
    for ($i=0; $i<count($placeholders); $i++) {

        if($bindTypes[$i]=='str'){// it's better to use integers as comparison 
            $stmt->bindValue($placeholders[$i], $parameters[$i], PDO::PARAM_STR);
        } else if($bindTypes[$i]=='int'){
            echo $placeholders[$i];
            $stmt->bindValue($placeholders[$i], $parameters[$i], PDO::PARAM_INT);
        }

    } 
    $stmt->execute();
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo json_encode($data, JSON_UNESCAPED_UNICODE );
}

关于php - 使用占位符时 PDO 执行速度较慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57183026/

相关文章:

php - 如何在Smarty中关闭html转义

mysql - 使用 JSON 数据通过数学对 SQL 行进行排序

php - 单例对于微博网站来说是一个好的设计模式吗?

php - 在 Ubuntu 12.04 LTS 上从 CakePHP 3 连接到 SQL Server

rhel6 上的 php pdo_informix - 未实现可选功能

php - 如何从我的数据库中过滤这些数据?

php - 如何在任何条件下将 php 数组传递给 postgres 查询

mysql - mysql查询中的两个where条件

php - 在 CakePHP 2 中不使用外键添加关联值

python - sqlalchemy - 使用 .csv 文件加入 MySQL 表