Ускорьте этот код - PHP / SQL - Short Code, но в настоящий момент он занимает невероятно много времени - PullRequest
2 голосов
/ 12 июля 2009

Правильно, этот код проходит через довольно большой многомерный массив (имеет около 28 000 строк и 16 частей).

Порядок событий:

  1. Проверьте, существуют ли данные в базе данных
  2. если он существует - обновите его новыми данными
  3. если его не существует - вставьте

Simple.

Но сейчас, чтобы пройти через это, я думаю, что прошло более 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++;     
}

UPDATE

Я только что выполнил профилирование одного из рядов:

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. Выполнять вставку / обновления оптом.

Вот окончательный код, который теперь занимает около 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 ]

1 голос
/ 12 июля 2009

Вы можете попробовать сгруппировать вставки и обновления в группы, чтобы код выполнял меньше запросов.

Например, вы можете сгруппировать все вставки в одну очень большую вставку или, возможно, сгруппировать каждые 100 вставок.

Также может помочь использование подготовленных утверждений, как предложил gradbot.

Кроме этого, не очень легко сказать, какая его часть является основной причиной медлительности. Вы должны использовать профилировщик, чтобы определить это, например, используя меньший набор данных, чтобы профилированный скрипт выполнялся в разумные сроки.

1 голос
/ 12 июля 2009

Вы можете сделать несколько вещей.

Попробуй это. Я не могу проверить это, но синтаксис должен быть правильным.

$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 был уникальным ключом.

0 голосов
/ 12 июля 2009

Это именно тот сценарий, для которого подготовленные заявления были сделаны:

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

Это реализовано в оболочках MySQLi и PDO. Он компилирует запрос только один раз и автоматически очищает данные, экономя время (как на этапе разработки, так и на этапе исполнения) и головную боль.

0 голосов
/ 12 июля 2009
  1. Профилировали ли вы этот запрос?

    "SELECT * FROM it_raw WHERE perfID = '" .addslashes ($ feed_array ['16'] [$ counter]). "'"

    Потому что вы запускаете его 28000 раз ... так что, если это НЕ ДЕЙСТВИТЕЛЬНО быстро, это вызовет у вас головную боль. Используйте синтаксис EXPLAIN и добавьте соответствующий индекс, если необходимо.

    EDIT : с профилем я имею в виду, что вы должны попытаться использовать EXPLAIN в приглашении mysql, чтобы увидеть, какой план выполнения оптимизатор запросов MySQL предлагает для этого запроса. Т.е. в командной строке выполните:

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

    То, что вы хотите увидеть, это то, что он использует индекс, и ТОЛЬКО индекс. Если вы не понимаете вывод, скопируйте и вставьте его сюда, чтобы я мог пройти с вами.

    ОБНОВЛЕНИЕ : Как видите, для КАЖДОЙ строки в вашем массиве данных требуется 0,07 секунды, плюс время для фактического запроса к базе данных, передачи результата и т. Д. Это примерно 28000 * 0,07 = 1960 секунды или 32 минуты, просто чтобы проверить, существуют ли данные или нет. Вам нужно придумать другой способ проверки, если данные уже существуют ... Одна, очень простая оптимизация может быть:

    EXPLAIN SELECT perfId FROM it_raw WHERE perfID = 210968;
    

    Таким образом, вы можете использовать индекс perfId, и вам не нужно посещать таблицу

  2. Если это возможно, старайтесь избегать запросов к базе данных для каждого запуска в цикле. Возможно, можно извлечь идентификаторы из базы данных в большой массив идентификаторов, которые поместятся в PHP-памяти? Это будет НАМНОГО быстрее, чем запрашивать базу данных для каждой строки в вашем массиве больших данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...