Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 使用占位符时的PDO慢速执行()阶段_Php_Mysql_Pdo - Fatal编程技术网

Php 使用占位符时的PDO慢速执行()阶段

Php 使用占位符时的PDO慢速执行()阶段,php,mysql,pdo,Php,Mysql,Pdo,我正在创建一些JSON端点,它们返回count和group by结果。对于这个端点,我使用PDO和命名占位符。使用命名占位符时,PHP响应在execute阶段最多需要6秒钟。当执行相同的查询并将值直接放入我的查询中时,响应几乎是即时的 我正在更新仍然使用mysql_query()来使用PDO语句的旧代码 <?php header("Access-Control-Allow-Origin: *"); header("Content-Type: application/

我正在创建一些JSON端点,它们返回count和group by结果。对于这个端点,我使用PDO和命名占位符。使用命名占位符时,PHP响应在
execute
阶段最多需要6秒钟。当执行相同的查询并将值直接放入我的查询中时,响应几乎是即时的

我正在更新仍然使用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 );
    }

以下是快速查询:

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


这是参数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

绑定值实际上不会对性能产生太大影响(一个准备好的语句会对数据库进行两次往返,但性能上的差异实际上是可以忽略的)。我建议您使用
JOIN
查询,这将简化
WHERE
子句,这可能会影响性能

您还可以直接指定连接对象的字符集,而不必使用
集名称
查询

如果查询速度慢,您应该查看表的索引-您是否正确使用了表上的主键?如果是,您仍然可以向您加入的字段抛出一些索引。例如,
字段
表的id和
上行
表的
文档id
都应该是主键

<?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;charset=utf8', 'username', 'password');
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$query = "SELECT t.meta, COUNT(*) as cnt 
          FROM field AS f 
          JOIN rep AS r
              ON f.id IN (r.rp1, r.rp2, r.rp3, r.rp4)
          JOIN t 
              ON t.meta = r.combination
          JOIN uplink AS u 
              ON u.doc_id = t.doc_id
          JOIN link AS l 
              ON l.id = u.link_id
          WHERE u.written = 1
            AND f.id = :field 
            AND t.earliest > :min 
            AND t.latest < :max 
          GROUP BY t.meta 
          ORDER BY cnt DESC 
          ");

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

适用于有类似问题的人;它被@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 );
}
$conditions=[]//按占位符上的类型插入的值
$parameters=[]//要在带有占位符的查询中执行的内容(带有命名占位符的查询的子字符串)
$bindTypes=[]//占位符应为的类型(函数将此作为第三个参数。它应为长类型(字符串给出错误,因此为if/else if块))
$placeholders=[]//仅包含:占位符。使用此命令告诉bindvalue()函数您希望将值X绑定到占位符:X
如果(isset($_GET[“min”])){
$mindate=(int)$_GET[“min”];
如果($mindate!=“”){
$conditions[]='t.earlime>=:mindate';
$parameters[]=$mindate;
$bindTypes[]='int';
$placeholders[]=':mindate';
}
}
如果(isset($_GET[“max”])){
$maxdate=(int)$\u GET[“max”];
如果($maxdate!=“”){
$conditions[]='t.latest>=:maxdate';
$parameters[]=$maxdate;
$bindTypes[]='int';
$placeholders[]=':maxdate';
}
}
如果($参数){
$stmt=$conn->prepare($querygraph);

对于($i=0;$i可能对速度没有帮助,但我使用
$db->setAttribute(PDO::MYSQL\u ATTR\u INIT\u命令,'SET NAMES UTF8')
为什么不改用
连接
呢?我在这里没有看到任何计时代码。如果您添加了一些代码,它将有助于确定时间消耗的位置。请使用适当的绑定类型分别绑定变量。我怀疑这是否有帮助,但也有一些rumos@Qirel;如何将查询结构更改为
JOIN
i改进
execute()
phase。如果我在PHPmyadmin中执行此查询,或者使用填充的值而不是占位符执行相同的查询,速度非常快。我使用占位符运行连接查询,时间是:开始:1563975139.986准备:1563975139.9869预执行:1563975139.9894后执行:1563975148.3492后取:1563975148.3492在没有占位符的情况下执行相同的查询时,我的时间安排是:开始:1563975287.6505准备:1563975287.6512预执行:1563975287.6537后执行:1563975287.6831后取:1563975287.6831我不认为该怪查询,它与
execute()有关
part,但我根本看不出有什么不对。@clunless\u船长,你能不能加一个简单的减法(四舍五入($start-$end))相信我,计算机在数学方面比计算机好得多humans@YourCommonSense;确保这些是四舍五入的值:这是用于带有占位符的运行。我必须使用一个浮点,在点后面有两个数字,因为查询本身实际上非常快。:开始:0准备:0执行前:0执行后:8.17 post fetch:8.17这是同一个查询的值,直接填写了占位符。我使用了相同的值:start:0 prepare:0 pre-execution:0 post-execution:0.02 post fetch:0.02我检查了JSON输出,它返回了相同的数据。@unless_船长您可能会错过我在您的问题下发布的建议。如果您I’我不知道你可以试一试case@YourCommonSense:你真是太棒了!!(我错过了最初的评论。为了让它在动态生成的查询中工作,需要进行一些修补。但是现在它工作了。我真不敢相信没有人教过我动态查询的
bindValues()
。非常感谢,你是个救命恩人!(我如何让你的评论成为一个答案,以便其他人能够找到它?)我想向你们建议这一点,因为MySQL在类型转换方面可能非常糟糕。过去我遇到过一个问题,删除数字字符串周围的引号会产生巨大的差异,但在我的例子中,我有数百个字段。在你们的例子中,我认为乐观主义者无法理解数字字符串,并且没有正确地优化查询。这会导致错误这是一个好主意,要求MySQL到<代码>解释< /Cord>执行。你也应该真正考虑Qirel告诉你的关于连接的东西,它可以帮助一些优化器。
<?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;charset=utf8', 'username', 'password');
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$query = "SELECT t.meta, COUNT(*) as cnt 
          FROM field AS f 
          JOIN rep AS r
              ON f.id IN (r.rp1, r.rp2, r.rp3, r.rp4)
          JOIN t 
              ON t.meta = r.combination
          JOIN uplink AS u 
              ON u.doc_id = t.doc_id
          JOIN link AS l 
              ON l.id = u.link_id
          WHERE u.written = 1
            AND f.id = :field 
            AND t.earliest > :min 
            AND t.latest < :max 
          GROUP BY t.meta 
          ORDER BY cnt DESC 
          ");

if ($parameters) {
    $stmt = $conn->prepare($query);
    $stmt->execute($parameters);
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
}
$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 );
}