加速这段代码 - PHP / SQL - 短代码,但目前需要很长时间

时间:2009-07-11 21:38:10

标签: php sql mysql optimization parsing

是的,这段代码经过了一个相当大的多维数组(大约有28,000行和16个部分)。

活动顺序:

  1. 检查数据库中是否存在数据
  2. 如果存在 - 使用新数据更新
  3. 如果不存在 - 插入
  4. 简单。

    但是现在要经历这个过程,我认为已经花费了超过30分钟而仍然正在进行。

    $counter = 0;
    $events = sizeof($feed_array['1'])-1;
    while($counter <= $events ) {
    
        $num_rows = mysql_num_rows(mysql_query("SELECT * FROM it_raw WHERE perfID = '".addslashes($feed_array['16'][$counter])."'")); 
        if($num_rows) {
            $eventDate=explode("/", $feed_array['1'][$counter]); //print_r($eventDate);
            $eventTime=explode(":", $feed_array['2'][$counter]); //print_r($eventTime);     
            $eventUnixTime=mktime($eventTime[0], $eventTime[1], "00", $eventDate[1], $eventDate[0], $eventDate[2]);
    
            mysql_query("UPDATE `it_raw` SET  
                        `eventtime` =       '".$eventUnixTime."',
                        `eventname` =       '".addslashes($feed_array['3'][$counter])."',
                        `venuename` =       '".addslashes($feed_array['4'][$counter])."',
                        `venueregion` =     '".addslashes($feed_array['5'][$counter])."',
                        `venuepostcode` =   '".addslashes($feed_array['6'][$counter])."',
                        `country` =         '".addslashes($feed_array['7'][$counter])."',
                        `minprice` =        '".addslashes($feed_array['8'][$counter])."',
                        `available` =       '".addslashes($feed_array['9'][$counter])."',
                        `link` =            '".addslashes($feed_array['10'][$counter])."',
                        `eventtype` =       '".addslashes($feed_array['11'][$counter])."',
                        `seaOnSaleDate` =   '".addslashes($feed_array['12'][$counter])."',
                        `perOnSaleDate` =   '".addslashes($feed_array['13'][$counter])."',
                        `soldOut` =         '".addslashes($feed_array['14'][$counter])."',
                        `eventImageURL` =   '".addslashes($feed_array['15'][$counter])."',
                        `perfID`=           '".addslashes($feed_array['16'][$counter])."'
                        WHERE  `perfID` = ".$feed_array['16'][$counter]." LIMIT 1 ;");
            echo "UPDATE ".$feed_array['16'][$counter].": ".addslashes($feed_array['3'][$counter])."\n";
        } else {
            $eventDate=explode("/", $feed_array['1'][$counter]); //print_r($eventDate);
            $eventTime=explode(":", $feed_array['2'][$counter]); //print_r($eventTime);     
            $eventUnixTime=mktime($eventTime[0], $eventTime[1], "00", $eventDate[1], $eventDate[0], $eventDate[2]);
            $sql = "INSERT INTO  `dante_tickets`.`it_raw` (
                    `id` ,
                    `eventtime` ,
                    `eventname` ,
                    `venuename` ,
                    `venueregion` ,
                    `venuepostcode` ,
                    `country` ,
                    `minprice` ,
                    `available` ,
                    `link` ,
                    `eventtype` ,
                    `seaOnSaleDate` ,
                    `perOnSaleDate` ,
                    `soldOut` ,
                    `eventImageURL` ,
                    `perfID`
                    )
                    VALUES (
                        NULL ,  
                        '".$eventUnixTime."',  
                        '".addslashes($feed_array['3'][$counter])."',  
                        '".addslashes($feed_array['4'][$counter])."',  
                        '".addslashes($feed_array['5'][$counter])."',  
                        '".addslashes($feed_array['6'][$counter])."',  
                        '".addslashes($feed_array['7'][$counter])."',  
                        '".addslashes($feed_array['8'][$counter])."',  
                        '".addslashes($feed_array['9'][$counter])."',  
                        '".addslashes($feed_array['10'][$counter])."',  
                        '".addslashes($feed_array['11'][$counter])."',  
                        '".addslashes($feed_array['12'][$counter])."',  
                        '".addslashes($feed_array['13'][$counter])."',  
                        '".addslashes($feed_array['14'][$counter])."',  
                        '".addslashes($feed_array['15'][$counter])."',  
                        '".addslashes($feed_array['16'][$counter])."'
                    );";
    
            mysql_query($sql) or die(mysql_error().":".$sql);
            echo "Inserted ".$feed_array['16'][$counter].": ".addslashes($feed_array['3'][$counter])."\n";
        }
        unset($sql);
        $counter++;     
    }
    

    更新

    我刚刚对其中一行进行了分析:

    mysql> EXPLAIN SELECT * FROM it_raw WHERE perfID = 210968;
    +----+-------------+--------+------+---------------+--------+---------+-------+------+-------+
    | id | select_type | table  | type | possible_keys | key    | key_len | ref   | rows | Extra |
    +----+-------------+--------+------+---------------+--------+---------+-------+------+-------+
    |  1 | SIMPLE      | it_raw | ref  | perfID        | perfID | 4       | const |    1 |       | 
    +----+-------------+--------+------+---------------+--------+---------+-------+------+-------+
    1 row in set (0.07 sec)
    

    更新2

    为了尝试“加速”事情,而不是立即执行UPDATE和INSERT语句,我现在将它们放在变量中(因此只有初始选择运行 - 检查重复 - 然后存储操作[插入或更新])。在循环结束时,它执行所有的陈述。

    除了现在,它出现MySQL错误,语法不正确。 (最初没有什么不对的。)

    我只是将mysql_query替换为:

    $ sql_exec。=“SELECT ....;”;

    这里有什么我缺少格式化的东西吗?

    更新3 好吧终于修好了 经验教训:

    1. 首先在数据库上进行逻辑搜索
    2. 批量执行插入/更新。
    3. 这是最终的代码,现在需要大约60秒才能运行(超过30分钟+)

      while($counter <= $events ) {
      
              $num_rows = mysql_num_rows(mysql_query("SELECT * FROM it_raw WHERE perfID = '".addslashes($feed_array['16'][$counter])."'")); 
              if($num_rows) {
                  $eventDate=explode("/", $feed_array['1'][$counter]); //print_r($eventDate);
                  $eventTime=explode(":", $feed_array['2'][$counter]); //print_r($eventTime);     
                  $eventUnixTime=mktime($eventTime[0], $eventTime[1], "00", $eventDate[1], $eventDate[0], $eventDate[2]);
      
                  $sql_exec[] =   "UPDATE `it_raw` SET `eventtime` = '".$eventUnixTime."',`eventname` = '".addslashes($feed_array['3'][$counter])."',`venuename` = '".addslashes($feed_array['4'][$counter])."',`venueregion` = '".addslashes($feed_array['5'][$counter])."',`venuepostcode` = '".addslashes($feed_array['6'][$counter])."',`country` = '".addslashes($feed_array['7'][$counter])."',`minprice` = '".addslashes($feed_array['8'][$counter])."',`available` = '".addslashes($feed_array['9'][$counter])."',`link` = '".addslashes($feed_array['10'][$counter])."',`eventtype` = '".addslashes($feed_array['11'][$counter])."',`seaOnSaleDate` = '".addslashes($feed_array['12'][$counter])."',`perOnSaleDate` = '".addslashes($feed_array['13'][$counter])."',`soldOut` =  '".addslashes($feed_array['14'][$counter])."',`eventImageURL` =   '".addslashes($feed_array['15'][$counter])."',`perfID`='".addslashes($feed_array['16'][$counter])."' WHERE `perfID` = ".$feed_array['16'][$counter]." LIMIT 1;";
                  echo "UPDATE ".$feed_array['16'][$counter].": ".addslashes($feed_array['3'][$counter])."\n";
              } else {
                  $eventDate=explode("/", $feed_array['1'][$counter]); //print_r($eventDate);
                  $eventTime=explode(":", $feed_array['2'][$counter]); //print_r($eventTime);     
                  $eventUnixTime=mktime($eventTime[0], $eventTime[1], "00", $eventDate[1], $eventDate[0], $eventDate[2]);
                  $sql_exec[] = "INSERT INTO  `it_raw` (`id` ,`eventtime` ,`eventname` ,`venuename` ,`venueregion` ,`venuepostcode` ,`country` ,`minprice` ,`available` ,`link` ,`eventtype` ,`seaOnSaleDate` ,
                          `perOnSaleDate` ,`soldOut` ,`eventImageURL` ,`perfID`) VALUES ( NULL ,'".$eventUnixTime."','".addslashes($feed_array['3'][$counter])."','".addslashes($feed_array['4'][$counter])."','".addslashes($feed_array['5'][$counter])."','".addslashes($feed_array['6'][$counter])."','".addslashes($feed_array['7'][$counter])."','".addslashes($feed_array['8'][$counter])."','".addslashes($feed_array['9'][$counter])."','".addslashes($feed_array['10'][$counter])."','".addslashes($feed_array['11'][$counter])."','".addslashes($feed_array['12'][$counter])."','".addslashes($feed_array['13'][$counter])."','".addslashes($feed_array['14'][$counter])."','".addslashes($feed_array['15'][$counter])."','".addslashes($feed_array['16'][$counter])."');";
      
                  //mysql_query($sql) or die(mysql_error().":".$sql);
                  echo "Inserted ".$feed_array['16'][$counter].": ".addslashes($feed_array['3'][$counter])."\n";
              }
              unset($sql);
              $counter++;     
          }
      
          foreach($sql_exec as $value) {
              mysql_query($value) or die (mysql_error().": ".$value); 
          }
      

4 个答案:

答案 0 :(得分:1)

你可以做很多事情。

试试这个。我无法测试它,但语法应该是正确的。

$counter = 0;
$events = sizeof($feed_array['1']) - 1;
while($counter <= $events )
{
  $eventDate = explode("/", $feed_array['1'][$counter]); //print_r($eventDate);
  $eventTime = explode(":", $feed_array['2'][$counter]); //print_r($eventTime);             
  $eventUnixTime = mktime($eventTime[0], $eventTime[1], "00", $eventDate[1], $eventDate[0], $eventDate[2]);

  $data = array(
    'eventtime'     => $eventUnixTime,
    'eventname'     => addslashes($feed_array['3'][$counter]),
    'venuename'     => addslashes($feed_array['4'][$counter]),
    'venueregion'   => addslashes($feed_array['5'][$counter]),
    'venuepostcode' => addslashes($feed_array['6'][$counter]),
    'country'       => addslashes($feed_array['7'][$counter]),
    'minprice'      => addslashes($feed_array['8'][$counter]),
    'available'     => addslashes($feed_array['9'][$counter]),
    'link'          => addslashes($feed_array['10'][$counter]),
    'eventtype'     => addslashes($feed_array['11'][$counter]),
    'seaOnSaleDate' => addslashes($feed_array['12'][$counter]),
    'perOnSaleDate' => addslashes($feed_array['13'][$counter]),
    'soldOut'       => addslashes($feed_array['14'][$counter]),
    'eventImageURL' => addslashes($feed_array['15'][$counter]),
    'perfID'        => addslashes($feed_array['16'][$counter]),
  );

  $update = array();
  foreach ($data as $key => $value)
    $update[] = "`$key` = '$value'";

  $sql = "INSERT INTO `dante_tickets`.`it_raw`" .
    '(`id`, `'. implode ('`,`', array_keys($data)) . '`) VALUES ' .
    '(NULL, ' . implode (',', $data) . ') ON DUPLICATE KEY UPDATE ' . 
    implode (',', $update);

  mysql_query($sql) or die(mysql_error().":".$sql);
  echo "Inserted or Updated".$feed_array['16'][$counter].": ".addslashes($feed_array['3'][$counter])."\n";

  unset($sql);
  $counter++;     
}

我忘了提到这要求perfID是一个唯一的密钥。

答案 1 :(得分:1)

您可以尝试将插入和更新分组到组中,以便代码运行较少的查询。

例如,您可以将所有插入分组到一个非常大的插入中,或者可以将每100个插入分组。

同样使用预备语句作为gradbot建议可能会有所帮助。

除此之外,要说它的哪一部分是造成缓慢的主要原因并不容易。您应该使用分析器来确定,例如通过使用较小的数据集,以便配置文件脚本在合理的时间内运行。

答案 2 :(得分:0)

  1. 您是否已对此查询进行了分析?

    “SELECT * FROM it_raw WHERE perfID ='”。addslashes($ feed_array ['16'] [$ counter])。“'”

    因为你运行它28000次..所以除非它真的很快,否则会让你头疼。使用EXPLAIN syntax并根据需要添加适当的索引。

    编辑:对于个人资料,我的意思是你应该尝试在mysql-prompt上使用EXPLAIN来查看MySQL查询优化器为此查询建议的执行计划。即,在提示符下,运行:

    EXPLAIN SELECT * FROM it_raw WHERE perfID = 426; 
    # Change this id to something existing and valid
    

    您希望看到的是它正在使用索引,而且只使用索引。如果您不理解输出,请将其复制并粘贴到此处,以便我随身携带。

    UPDATE :正如您所看到的,数据数组中的每一行都需要0.07秒,加上实际查询数据库,传输结果等的时间。这大约是28000 * 0.07 = 1960秒,或32分钟,只是为了检查数据是否存在。你需要提出另一种方法来检查数据是否已经存在......一个非常简单的优化可能是:

    EXPLAIN SELECT perfId FROM it_raw WHERE perfID = 210968;
    

    这样,您可以在perfId上使用索引而不需要访问表

  2. 如果可能,请尝试避免在循环中每次运行时查询数据库。也许有可能将数据库中的id提取到适合PHP内存的大量id中?这比为大数据阵列中的每一行查询数据库要快得多。

答案 3 :(得分:0)

这正是制作prepared statements的情景:

$prepared_statement =
    $DB->prepare('INSERT INTO table(column, column) VALUES(?, ?)');
loop {
    $prepared_statement->execute(array('value1', 'value2');
}

它是在MySQLi和PDO包装器中实现的。它只编译一次查询并自动清理给定的数据,节省时间(包括开发和执行)和头痛。