Php Mysql-执行查询花费太多时间

Php Mysql-执行查询花费太多时间,php,mysql,sql,query-optimization,execution,Php,Mysql,Sql,Query Optimization,Execution,首先,我的mysql表定义如下: 订单(333000多条记录) 订单状态(70条记录) 订单状态历史记录(222000多条记录) 订单\状态\历史记录表格包含每个订单的不同状态 `orders_status_id` int(11) `orders_status_name` varchar(32) PRIMARY KEY (`orders_status_id`,`language_id`) 因此,我想得到的是以下三个选项: 订单必须有shipping\u模块pickup\u-pick

首先,我的mysql表定义如下:

订单(333000多条记录)

订单状态(70条记录)

订单状态历史记录(222000多条记录)

订单\状态\历史记录表格包含每个订单的不同状态

  `orders_status_id` int(11)
  `orders_status_name` varchar(32)
  PRIMARY KEY (`orders_status_id`,`language_id`)
因此,我想得到的是以下三个选项:

  • 订单必须有
    shipping\u模块
    pickup\u-pickup或pickup2\u-pickup2
  • orders\u status\u history。orders\u status\u id
    必须具有以下状态7、21、34、40
  • 但是
    orders\u status\u history。orders\u status\u id
    不得具有以下状态33,53
  • 解释问题: 假设有10个订单,并且他们在其生命中的某个时间具有以下状态:

  • [7,34,41,48]
  • [20,40,34,57,14,25]
  • [53,7,40,5]
  • [41,25,4]
  • [1,2,3,4]
  • [34,4,33,53,7]
  • [4,21,31,7,8]
  • [78,15,45,40]
  • [53,40,31,21,7]
  • [33,74,54,7,22]
  • 所以我要提取的顺序是1,2,7,8,因为这个顺序包含7,31,21或40,而不是53,33

    我尝试了以下查询:

    1.)

    此查询的性能正常,但它获得了所有结果(1200条记录),但没有筛选3个选项

    (二)

    它也和前一个一样工作,没有过滤第三个选项

    (三)

    此查询执行时间太长,无法执行

    (四)

    此查询的工作方式与第一个太查询未筛选第三个选项相同

    所以后来我用php尝试了一下

    $sql = "SELECT o.orders_id, osh.orders_status_history_id
            FROM 
                orders AS o, 
                orders_status_history AS osh
            WHERE ( 
                o.shipping_module LIKE  '%pickup_pickup%'
                OR o.shipping_module LIKE  '%pickup2_pickup2%'
               )
            AND o.orders_id = osh.orders_id
            AND osh.orders_status_id IN (7, 21, 31, 40) 
            AND osh.orders_status_id != 33
            AND osh.orders_status_id != 53";
    $sql    = mysql_query($sql);
    while ($row = mysql_fetch_array($sql)){
        $row["orders_id"]);
        if(getOrderStatus($row["orders_id"]))
            echo "<br/>".$row["orders_id"];
    }
    
    function getOrderStatus($order){
        $sql    = "SELECT orders_status_id FROM orders_status_history WHERE orders_id = ".$order;
        echo "<br/> Sql Query : ".$sql;
         $sql = mysql_query($sql);
         while ($status     = mysql_fetch_array($sql))
           if((int)$status["orders_status_id"] == 33 || (int)$status["orders_status_id"] == 53)
                return false;
        return true;
    }
    
    $sql=“选择o.orders\u id、osh.orders\u status\u history\u id
    从…起
    命令作为o,
    订单\状态\历史记录为osh
    何处(
    o、 装运模块,如“%pickup\u pickup%”
    或像“%pickup2\u pickup2%”这样的o.shipping\u模块
    )
    和o.orders\u id=osh.orders\u id
    和osh.orders\u status\u id IN(7,21,31,40)
    和osh.orders\u status\u id!=33
    以及osh.orders_status_id!=53”;
    $sql=mysql\u查询($sql);
    while($row=mysql\u fetch\u数组($sql)){
    $row[“订单id”);
    if(getOrderStatus($row[“orders\u id”]))
    echo“
    “$row[“orders_id”]; } 函数getOrderStatus($order){ $sql=“从订单状态历史记录中选择订单状态id,其中订单id=”.$order; echo“
    Sql查询:”.$Sql; $sql=mysql\u查询($sql); 而($status=mysql\u fetch\u数组($sql)) 如果((int)$status[“订单状态标识”]==33(int)$status[“订单状态标识”]==53) 返回false; 返回true; }
    此代码花费的时间太多,超过30m。I
    设置时间限制(0)


    注意:我只能使用Mysql,因为我们的php版本是4.9

    这里有一种方法可以获得符合您标准的订单:

    SELECT o.orders_id
    FROM orders o JOIN
         orders_status_history osh
         ON o.orders_id = osh.orders_id
    WHERE (o.shipping_module LIKE  '%pickup_pickup%' OR
           o.shipping_module LIKE  '%pickup2_pickup2%'
          ) AND
          osh.orders_status_id IN (7, 21, 31, 40, 33, 53)
    GROUP BY o.orders_id
    HAVING SUM( osh.orders_status_id IN (33, 53) ) = 0;
    
    其中
    仅选择您关心的状态。
    拥有
    可以确保你没有最后两个


    如果您想要订单或订单行的详细信息,那么您需要重新加入这些表。

    除了PHP4.9已经过时(您应该建议您的老板升级)之外,您是否曾经对您的查询运行过
    EXPLAIN…
    ?为表格设置了什么类型的索引?
    osh.orders\u status\u id IN(7,21,31,40)和osh.orders\u status\u id NOT IN(33,53)
    没有任何意义,就好像某个东西是(7,21,31,40)而不是(33,53)一样。其他查询以不同的形式呈现相同的内容。所以你确定你的reslut中仍然有33,53的记录吗?我已经有好几年没有看到有人使用PHP4了。。。它已经严重过时,而且完全不安全。此外,它不应影响查询。。正如@paul所提到的,在询问前使用
    解释
    。它应该,嗯,解释它做什么和它使用什么索引。。。它可能缺少一些东西谢谢你帮了我。我们使用的是oscommerce 2.2,没有设置任何索引:(.你能给我一个演示,说明我从未尝试过,也不知道它。你应该添加索引…而且oscommerce 2.2大约有9年的历史了吗?
    
      `orders_status_id` int(11)
      `orders_status_name` varchar(32)
      PRIMARY KEY (`orders_status_id`,`language_id`)
    
    SELECT * 
    FROM orders AS o, orders_status_history AS osh
    WHERE (
           o.shipping_module LIKE  '%pickup_pickup%'
           OR o.shipping_module LIKE  '%pickup2_pickup2%'
       )
    AND o.orders_id = osh.orders_id
    AND osh.orders_status_id
    IN ( 7, 21, 31, 40 ) AND osh.orders_status_id
    NOT IN (33, 53)
    
    SELECT * 
    FROM orders AS o, orders_status_history AS osh
    WHERE (
           o.shipping_module LIKE  '%pickup_pickup%'
           OR o.shipping_module LIKE  '%pickup2_pickup2%'
       )
    AND o.orders_id = osh.orders_id
    AND osh.orders_status_id IN (7, 21, 31, 40) 
    AND osh.orders_status_id != 33
    AND osh.orders_status_id != 53
    
    SELECT * 
    FROM orders AS o, orders_status_history AS osh
    WHERE (
           o.shipping_module LIKE  '%pickup_pickup%'
           OR o.shipping_module LIKE  '%pickup2_pickup2%'
       )
    AND o.orders_id = osh.orders_id
    AND osh.orders_status_id IN (7, 21, 31, 40) 
    AND osh.orders_status_id NOT IN (
                                     SELECT so.orders_id 
                                     FROM orders AS so, orders_status_history AS sosh
                                     WHERE (
                                            so.shipping_module LIKE  '%pickup_pickup%'
                                            OR so.shipping_module LIKE  '%pickup2_pickup2%'
                                            )
                                     AND sosh.orders_status_id != 33
                                 )
    
    SELECT * 
    FROM orders AS o, orders_status_history AS osh
    WHERE (
           o.shipping_module LIKE  '%pickup_pickup%'
           OR o.shipping_module LIKE  '%pickup2_pickup2%'
       )
    AND o.orders_id = osh.orders_id
    AND osh.orders_status_id = 7
    AND osh.orders_status_id = 21
    AND osh.orders_status_id = 31
    AND osh.orders_status_id = 40
    AND osh.orders_status_id != 33
    AND osh.orders_status_id != 53
    
    $sql = "SELECT o.orders_id, osh.orders_status_history_id
            FROM 
                orders AS o, 
                orders_status_history AS osh
            WHERE ( 
                o.shipping_module LIKE  '%pickup_pickup%'
                OR o.shipping_module LIKE  '%pickup2_pickup2%'
               )
            AND o.orders_id = osh.orders_id
            AND osh.orders_status_id IN (7, 21, 31, 40) 
            AND osh.orders_status_id != 33
            AND osh.orders_status_id != 53";
    $sql    = mysql_query($sql);
    while ($row = mysql_fetch_array($sql)){
        $row["orders_id"]);
        if(getOrderStatus($row["orders_id"]))
            echo "<br/>".$row["orders_id"];
    }
    
    function getOrderStatus($order){
        $sql    = "SELECT orders_status_id FROM orders_status_history WHERE orders_id = ".$order;
        echo "<br/> Sql Query : ".$sql;
         $sql = mysql_query($sql);
         while ($status     = mysql_fetch_array($sql))
           if((int)$status["orders_status_id"] == 33 || (int)$status["orders_status_id"] == 53)
                return false;
        return true;
    }
    
    SELECT o.orders_id
    FROM orders o JOIN
         orders_status_history osh
         ON o.orders_id = osh.orders_id
    WHERE (o.shipping_module LIKE  '%pickup_pickup%' OR
           o.shipping_module LIKE  '%pickup2_pickup2%'
          ) AND
          osh.orders_status_id IN (7, 21, 31, 40, 33, 53)
    GROUP BY o.orders_id
    HAVING SUM( osh.orders_status_id IN (33, 53) ) = 0;