2010-07-22 3 views
1

У меня есть текстовый файл 800 Мб с 18990,870 строками в нем (каждая строка - это запись), что мне нужно выбрать определенные записи, и если есть совпадение, напишите их в базу данных.Как ускорить обработку огромного текстового файла?

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

Мой PHP читает построчно следующим образом:

$fp2 = fopen('download/pricing20100714/application_price','r'); 
if (!$fp2) {echo 'ERROR: Unable to open file.'; exit;} 
while (!feof($fp2)) { 
$line = stream_get_line($fp2,128,$eoldelimiter); //use 2048 if very long lines 
if ($line[0] === '#') continue; //Skip lines that start with # 
    $field = explode ($delimiter, $line); 
list($export_date, $application_id, $retail_price, $currency_code, $storefront_id) = explode($delimiter, $line); 
if ($currency_code == 'USD' and $storefront_id == '143441'){ 
// does application_id exist? 
$application_id = mysql_real_escape_string($application_id); 
$query = "SELECT * FROM jos_mt_links WHERE link_id='$application_id';"; 
$res = mysql_query($query); 
if (mysql_num_rows($res) > 0) { 
echo $application_id . "application id has price of " . $retail_price . "with currency of " . $currency_code. "\n"; 
} // end if exists in SQL 
} else 
{ 
// no, application_id doesn't exist 
} // end check for currency and storefront 
} // end while statement 
fclose($fp2); 
+0

Кто большой таблица jos_mt_links? Просто получить все записи один раз и выполнить проверку, не обращаясь к базе данных. – Andreas

ответ

1

Вы анализируете строку ввода дважды, выполняя два взрыва в строке.Я хотел бы начать с удаления первой строки:

$field = explode ($delimiter, $line); 
list($export_date, ...., $storefront_id) = explode($delimiter, $line); 

Кроме того, если вы используете только запрос, чтобы проверить на матч на основе вашего состояния, не используйте SELECT * использовать что-то вроде этого:

"SELECT 1 FROM jos_mt_links WHERE link_id='$application_id';" 

Вы также можете, как предложил Брэндон Хорсли, буферировать набор значений application_id в массиве и изменить ваш оператор select, чтобы использовать предложение IN, тем самым уменьшая количество выполняемых запросов.

8

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

Если пространство и IO не являются проблемой, вы можете просто вслепую записать все записи 19M в новую таблицу промежуточных БД, добавить индексы, а затем выполнить сопоставление с фильтром?

+0

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

+3

@kitenski: Вы пытались? Я имею в виду, что это всего около 10 строк кода. И, делая последовательно 19M, асинхронная вставка будет быстрее, чем 19M случайных выборок. – Andreas

3

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

+0

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

+0

Не прочитывать каждую строку и записывать в базу данных, но используя инструмент, который в большинстве баз данных приходится наваготно загружать файл сразу. После этого у вас есть возможность добавить нужный индекс и, наконец, искать нужные вам данные, выбирая/вставляя в таблицу баз данных \ s. – Kuberchaun

0

Базы данных построены и спроектированы таким образом, чтобы справляться с большими объемами данных, а PHP - нет. Вам нужно переоценить, как вы храните данные.

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

2

19M строк в DB замедлит работу, если БД не была разработана должным образом. Вы все равно можете использовать текстовые файлы, если они правильно разделены. Повторное создание нескольких небольших файлов, основанных на определенных параметрах, может быть сохранено правильно.

В любом случае PHP не лучший язык для ввода-вывода файлов и обработки, он намного медленнее, чем Java для этой задачи, в то время как простой старый C будет одним из самых быстрых для работы. PHP должен быть ограничен генерируемым динамическим веб-выходом, а основная обработка должна быть в Java/C. В идеале это должна быть служба Java/C, которая генерирует выходные данные, и PHP, используя этот канал для генерации вывода HTML.

1

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

0

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

Например, нагрузка 1000 записей, которые соответствуют валюте USD и витрину в то время, в массив и выполнить запрос, как:

'select link_id from jos_mt_links where link_id in (' . implode(',', application_id_array) . ')'

Это возвращает список тех записей, которые в база данных. Кроме того, вы можете изменить sql, чтобы он был not in, чтобы получить список тех записей, которые не находятся в базе данных.

1

Препроцесс с sed и/или awk?