2010-08-04 4 views
6

У меня есть файл csv, в котором содержится 3,5 миллиона кодов.
Я должен отметить, что это только КАЖДОЙ будет один раз.Этот код должен занять более 3,5 миллионов строк, как я могу сделать его более эффективным?

CSV-выглядит

age9tlg, 
rigfh34, 
... 

Вот мой код:

ini_set('max_execution_time', 600); 
ini_set("memory_limit", "512M"); 
$file_handle = fopen("Weekly.csv", "r"); 
while (!feof($file_handle)) { 
    $line_of_text = fgetcsv($file_handle); 

    if (is_array($line_of_text)) 
     foreach ($line_of_text as $col) { 
      if (!empty($col)) { 
       mysql_query("insert into `action_6_weekly` Values('$col', '')") or die(mysql_error()); 
      } 
    } else { 
     if (!empty($line_of_text)) { 
      mysql_query("insert into `action_6_weekly` Values('$line_of_text', '')") or die(mysql_error()); 
     } 
    } 
} 
fclose($file_handle); 

этот код собирается умереть часть пути через меня? Будет ли моя память и максимальное время выполнения достаточно высокой?

NB: Этот код будет запущен на моем локальном хосте, а база данных находится на том же ПК, поэтому латентность не является проблемой.


Update:
вот другой возможной реализации. Это один делает это в объемных вставках 2000 записей

$file_handle = fopen("Weekly.csv", "r"); 
$i = 0; 
$vals = array(); 
while (!feof($file_handle)) { 
    $line_of_text = fgetcsv($file_handle); 

    if (is_array($line_of_text)) 
     foreach ($line_of_text as $col) { 
      if (!empty($col)) { 
       if ($i < 2000) { 
        $vals[] = "('$col', '')"; 
        $i++; 
       } else { 
        $vals = implode(', ', $vals); 
        mysql_query("insert into `action_6_weekly` Values $vals") or die(mysql_error()); 
        $vals = array(); 
        $i = 0; 
       } 
      } 
     } else { 
     if (!empty($line_of_text)) { 
      if ($i < 2000) { 
       $vals[] = "('$line_of_text', '')"; 
       $i++; 
      } else { 
       $vals = implode(', ', $vals); 
       mysql_query("insert into `action_6_weekly` Values $vals") or die(mysql_error()); 
       $vals = array(); 
       $i = 0; 
      } 
     } 
    } 
} 
fclose($file_handle); 

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


Update 2
так, ив нашел я могу использовать

LOAD DATA LOCAL INFILE 'C:\\xampp\\htdocs\\weekly.csv' INTO TABLE `action_6_weekly` FIELDS TERMINATED BY ';' ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY ','(`code`) 

но вопрос в настоящее время является то, что я был неправ о формате CSV, это на самом деле 4-кодов, а затем разрыв строки, так fhroflg, qporlfg, vcalpfx, rplfigc,
vapworf, flofigx, apqoeei, clxosrc,
...

, поэтому мне нужно указать две ЛИНИИ, ОГРАНИЧЕННЫЕ
Этот вопрос был разветвлен до Here.


Update 3
Установка этого делать объемные вставки из 20k строк, используя

while (!feof($file_handle)) { 
    $val[] = fgetcsv($file_handle); 
    $i++; 
    if($i == 20000) { 
     //do insert 
     //set $i = 0; 
     //$val = array(); 
    } 
} 

//do insert(for last few rows that dont reach 20k 

, но он умирает в этот момент, потому что по какой-то причине $ Валу содержит 75K строк и идеи почему?
Обратите внимание, что приведенный выше код упрощен.

+1

Должно быть очевидно, что крайне сложно вставить 3,5 миллиона записей в последовательности. SQL Server имеет специальную семантику массовой копии для больших объемных вставок; вы должны искать что-то подобное в MySQL. – mquander

+0

вы можете запускать его по частям, таким как X количество записей каждые X минут, если вам не нужно запускать все это сразу. http://dev.mysql.com/doc/refman/5.0/en/mysqlimport.html – Prix

+0

Итак, я пробовал делать объемную вставку на 200 тыс. строк, да интересная ошибка; Сервер MySQL ушел lol – Hailwood

ответ

21

Я сомневаюсь, что это будет популярный ответ, но я бы ваш PHP приложений запустить mysqlimport на файл CSV. Разумеется, он оптимизирован далеко за рамки того, что вы будете делать в php.

+9

А классический «Я собираюсь занять это». Тактика работает со мной: +1. – Artefacto

+0

И можно ли установить две строки, завершенные? Учитывая, что это отображает непосредственно в Load Data In File – Hailwood

3

этот код будет умирать часть пути через меня? будет ли моя память и макс времени выполнения достаточно высокой?

Почему бы вам не попробовать?

Вы можете настроить как память (memory_limit), так и время выполнения (max_execution_time), поэтому, если вам действительно нужно это использовать, это не должно быть проблемой.

Обратите внимание, что MySQL поддерживает вставку замедленное и несколько строк:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9); 

http://dev.mysql.com/doc/refman/5.1/en/insert.html

0

Вы должны аккумулировать значения и вставлять их в базу данных все сразу в конце или в пакетах каждые х записей. Выполнение одного запроса для каждой строки означает 3,5 миллиона SQL-запросов, каждый из которых несет некоторые накладные расходы.

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

Реальный ответ, хотя ответ на вызов evilclown, импортирование в MySQL из CSV уже является проблемой.

+0

csv не в правильном формате, ему не хватает некоторых столбцов. – Hailwood

+0

@ Hailwood Это не должно быть проблемой, см. Примеры в руководстве: 'LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata (col1, col2, ...);' – deceze

+0

не могли бы вы сказать мне, что мне нужно? написать? CSV-в формате кода (новой строки) кода (новой строки) кода (перевод строки) код (перевод строки) , но мне нужно вставить в формате («», код , 0) – Hailwood

0

Надеюсь, что веб-клиент не ждет ответа на это. Помимо вызова уже упомянутой утилиты импорта, я начал бы это делать как работу и сразу же возвращать обратную связь клиенту. Обновите цикл петли в процентах, чтобы конечный пользователь мог проверить статус, если вы абсолютно должны это сделать.

0

2 возможных способа.

1) Пакет процесса, затем запланированное задание импортирует файл при обновлении статуса. Таким образом, вы можете иметь страницу, которая продолжает проверять статус и обновлять себя, если статус еще не 100%. У пользователей будет актуальное обновление того, сколько было сделано. Но для этого вам нужно получить доступ к ОС, чтобы настроить задачу расписания. И задача будет работать без дела, когда импортировать нечего.

2) Имейте страницу с дескриптором 1000 строк (или любое количество N строк ... вы решите), а затем отправьте Java-скрипт в браузер, чтобы обновить себя новым параметром, чтобы сообщить скрипту обрабатывать следующие 1000 строк. Вы также можете отображать статус для пользователя, пока это происходит. Проблема только в том, что если страница каким-то образом не обновляется, то импорт останавливается.

1
  1. убедитесь, что не нет индексов на вашем столе, а индексы замедлят вставки (добавить индексы после того как вы сделали все вставки)
  2. , а не создавать новое заявление SQL в каждом вызове цикла try и Prepare the SQL Заявление вне цикла и выполнить этот подготовленный оператор с параметрами внутри цикла. В зависимости от базы данных это может быть быстрее.

Я делал это при импорте большой базы данных Access в Postgres, используя perl, и получил время вставки до 30 секунд. Я бы использовал инструмент импортера, но мне хотелось, чтобы Perl применял некоторые правила при вставке.

+1

вы также можете отключить индексы – Cfreak

Смежные вопросы