Как ускорить обработку огромного текстового файла? - PullRequest
1 голос
/ 22 июля 2010

У меня есть текстовый файл 800 Мб с 18 990 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);

Ответы [ 8 ]

8 голосов
/ 22 июля 2010

Предполагается, что проблема в производительности связана с тем, что он выдает запрос для каждого application_id с указанием доллара США и вашей витрины.

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

3 голосов
/ 22 июля 2010

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

2 голосов
/ 22 июля 2010

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

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

1 голос
/ 23 июля 2010

препроцесс с помощью sed и / или awk?

1 голос
/ 23 июля 2010

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

$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, тем самым сократив количество выполняемых запросов.

1 голос
/ 22 июля 2010

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

0 голосов
/ 23 июля 2010

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

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

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

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

0 голосов
/ 22 июля 2010

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

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

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