За последние 24 часа нас посетили 18325 программистов и 1600 роботов. Сейчас ищут 962 программиста ...

Оптимизация работы скрипта

Тема в разделе "Прочие вопросы по PHP", создана пользователем mozzart-live, 25 окт 2013.

  1. mozzart-live

    mozzart-live Новичок

    С нами с:
    13 авг 2013
    Сообщения:
    8
    Симпатии:
    0
    Адрес:
    Челябинск
    Здравствуйте, есть такая задачка:
    1. имеем огромный файл xls (прайс)
    2. база на мускуле
    3. шаред хостинг (Nginx frontend + Apache backend)

    Что делаем:
    1. через библиотеку превращаем xls -> csv
    2. читаем файл через fgetcsv
    3. проверяем на наличие товара в БД, если нет товара, то записываем, если есть - обновляем

    сейчас скрипт на этом этапе жрет много памяти + проц (конечно, на этапе добавления в БД)
    как можно оптимизировать работу такого приложения?
     
  2. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    какой из этапов жрет столько памяти?
    выход - читайте файл построчно.
     
  3. mozzart-live

    mozzart-live Новичок

    С нами с:
    13 авг 2013
    Сообщения:
    8
    Симпатии:
    0
    Адрес:
    Челябинск
    Так функция fgetcsv и так читает построчно.
     
  4. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    код в студию тогда
     
  5. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Код (Text):
    1. если нет товара, то записываем
    Объединить несколько запросов insert в один.
     
  6. mozzart-live

    mozzart-live Новичок

    С нами с:
    13 авг 2013
    Сообщения:
    8
    Симпатии:
    0
    Адрес:
    Челябинск
    Код (Text):
    1. $warehousQuery = $this->db->get('shops_warehous', 1);
    2.                             $warehousRow = $warehousQuery->row_array();
    3.                            
    4.                             $handle = @fopen($fileCache, "r");
    5.                             if ($handle) {
    6.                                 $fopenLog = fopen($_SERVER['DOCUMENT_ROOT'] . "/excel_parser/" . $_POST['filename'] . ".log","w+") or die("Невозможно открыть / создать лог файл");
    7.                                 $counter = 0;
    8.                                 while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
    9.                                    
    10.                                     $connectValue = ($connectFieldName == 'id') ? intval($data[$connectFieldKey]) : trim($data[$connectFieldKey]);
    11.                                    
    12.                                     if (!empty($connectValue))
    13.                                     {
    14.                                         $this->db->select('id');
    15.                                         $resultQuery = $this->db->get_where('shops_products', array ($connectFieldName => $connectValue), 1);
    16.                                        
    17.                                         $dataRow = Array ();
    18.                                        
    19.                                         foreach ($allFields as $keyField => $fieldName)
    20.                                         {
    21.                                             if ($fieldName != "id")
    22.                                             {
    23.                                                 $fieldValue = trim($data[$keyField]);
    24.                                                 if ($fieldName == "price" || $fieldName == "old_price")
    25.                                                 {
    26.                                                     $fieldValue = floatval($fieldValue);
    27.                                                 }
    28.                                                 elseif ($fieldName == "warehous_val")
    29.                                                 {
    30.                                                     $fieldValue = preg_replace('/[^0-9]/', '', $fieldValue);
    31.                                                 }
    32.                                                 elseif ($fieldName == "name" && isset($_POST['settings_change_url']) && !empty($_POST['settings_change_url']))
    33.                                                 {
    34.                                                     $dataRow['url'] = translit_url($fieldValue);
    35.                                                 }
    36.                                                 $dataRow[$fieldName] = $fieldValue;
    37.                                             }
    38.                                         }
    39.                                        
    40.                                         $dataProduct = $dataRow;
    41.                                         unset($dataProduct['warehous_val']);
    42.                                        
    43.                                         if ($resultQuery->num_rows() == 1)
    44.                                         {
    45.                                             $resultRow = $resultQuery->row_array();
    46.                                            
    47.                                            
    48.                                             $this->db->where('id', $resultRow['id']);
    49.                                             $this->db->update('shops_products', $dataProduct);
    50.                                            
    51.                                             if (isset($dataRow['warehous_val']))
    52.                                             {
    53.                                                 $this->db->where('product_id', $resultRow['id']);
    54.                                                 $this->db->delete('shops_warehous_data');
    55.  
    56.                                                 $this->db->insert('shops_warehous_data', Array (
    57.                                                     'product_id' => $resultRow['id'],
    58.                                                     'warehous_id' => $warehousRow['id'],
    59.                                                     'variant_id' => 0,
    60.                                                     'count' => $dataRow['warehous_val']
    61.                                                 ));
    62.                                             }
    63.                                             fwrite($fopenLog, 'Обновлен товар #' . $resultRow['id'] . "<br/>");
    64.                                            
    65.                                            
    66.                                         }
    67.                                         elseif (isset($_POST['settings_add']) && !empty($_POST['settings_add']))
    68.                                         {
    69.                                             if (!empty($dataProduct['name']) && !empty($dataProduct['price']))
    70.                                             $this->db->insert('shops_products', $dataProduct);
    71.                                             $insertId = $this->db->insert_id();
    72.                                             if (isset($dataRow['warehous_val']))
    73.                                             {
    74.                                                 $this->db->insert('shops_warehous_data', Array (
    75.                                                     'product_id' => $insertId,
    76.                                                     'warehous_id' => $warehousRow['id'],
    77.                                                     'variant_id' => 0,
    78.                                                     'count' => $dataRow['warehous_val']
    79.                                                 ));
    80.                                             }
    81.                                             fwrite($fopenLog, 'Добавлен новый товар #' . $insertId . "<br/>");
    82.                                         }
    83.  
    84.                                         unset($resultQuery);
    85.                                         unset($resultRow);
    86.                                        
    87. //                                        $counter++;
    88. //                                        if ($counter == 20) break;
    89.                                     }
    90.                                 }
    91.                                 fclose($fopenLog);
    92.                                 fclose($handle);
     
  7. mozzart-live

    mozzart-live Новичок

    С нами с:
    13 авг 2013
    Сообщения:
    8
    Симпатии:
    0
    Адрес:
    Челябинск
    Всем спасибо. Сделал следующее:
    1. Все запросы на insert и update собрал в один
    2. получаю все записи у которых не пустое связующее поле, загоняю значения в массив - избавляюсь от частых select'ов
     
  8. mac0s

    mac0s Новичок

    С нами с:
    25 окт 2013
    Сообщения:
    3
    Симпатии:
    0
  9. Slavka

    Slavka Активный пользователь

    С нами с:
    1 окт 2013
    Сообщения:
    722
    Симпатии:
    41
    если вы все данные либо добавляете либо обновляете-
    а почему бы перед началом не чистить таблицу .. а потом тупо инсертить
    помойму так быстрее будет
     
  10. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    Если id заново добавляемого товара не изменится - то да, так лучше. Если изменится, то не вариант - на товар могут быть ссылки.
     
  11. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Кстати, для обновления/добавления есть http://phpclub.ru/mysql/doc/replace.html, если уж задача - оптимизировать, то логично будет перенести обновление на мускуль.
     
  12. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    Замечания:
    • REPLACE работает как DELETE + INSERT, то есть если у нас есть foreign keys с каскадным удалением, или триггеры на удаление, то всёпиздец! Тут больше подойдет INSERT... ON DUPLICATE KEY UPDATE
      Ну и, минуточку, раз мы всё равно все записи удаляем, то один раз TRUNCATE, а затем n раз INSERT будет гораздо быстрее чем n раз REPLACE. Короче, совет неудачный.
    • И replace и insert...on duplicate расчитывают на совпадение первичного/уникального ключа. Если уникальность обеспечена автоинкрементом, который рождается в процессе накатывания данных, то у нас нет зацепок для подобной "оптимизации".
    • Топикстартер вобщето плачет о большом расходе памяти. Если собирать данные в большие пучки для быстрой вставки, тогда память конечно тратится. Тут наверное надо искать компромисс, экспериментировать с размером "пучка".
    • Проверять каждый id на стороне PHP это гарантированные тормоза! Стоит попробовать вставлять ВСЕ данные из файла во временную таблицу, затем одним запросом сливать ее в целевую с INSERT...ON DUPLICATE UPDATE. (Или INSERT...IGNORE -- автору видней)
    Кстати, если реализуешь трюк со временной таблицей, то LOAD DATA INFILE тебе в помощь!
    Удачи!
     
  13. deblogger

    deblogger Новичок

    С нами с:
    11 июл 2013
    Сообщения:
    200
    Симпатии:
    0
    Бред полнейший. Такие операции не делаются через веб-интерфейс. Никакие апачи-хреначи тут не валялись. Из текстовых данных делается файл типа дампа с той лишь разницей что insert снабжен словом ignore и всеми необходимыми условиями. Теперь заходим в шелл, или если не есть - в хостинг до PMA, или что там есть и забиваем этот заброс в режиме импорта таблиц.

    А, так у вас там и id есть? В том cvs. Ну тогда это репликация и делается она еще раз по-другому.

    Догадаться реплицировать через скрипт - это могучий ход. Особенно впечатляет толпа советчиков как это лучше сделать.

    Добавлено спустя 6 минут 40 секунд:
    Все блин элементарно http://dev.mysql.com/doc/refman/5.0/en/replication-options- ... e-do-table

    Нет шелла? Дамп табли в локаль, там реплика и обратно на сервер.

    Добавлено спустя 1 минуту 2 секунды:
    Ежу понятно из csv сперва надо создать таблицу.
     
  14. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    ты откуда взялся такой сердитый? :D
    кто сказал, что это репликация? топикстартер вроде спросил как быстро заливать csv в существующую таблицу.
    апач действительно непричем.