2010-07-22 102 views
1

我有一個800MB的文本文件,其中有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); 
+0

誰是jos_mt_links表? 只需檢索一次所有條目並在不訪問數據庫的情況下執行檢查。 – Andreas 2010-07-22 14:24:23

回答

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';" 

正如Brandon Horsley所建議的,您也可以將一組application_id值緩存在數組中,並將您的select語句修改爲使用IN子句,從而減少正在執行的查詢數。

8

在猜測,性能問題,是因爲它發出與美元,你的店面每APPLICATION_ID查詢。

如果空間和IO是不是一個問題,你可能只是盲目地寫所有19M記錄到一個新的臨時數據庫表,添加索引,然後做一個過濾器匹配?

+0

確實讀取每一行並寫入數據庫,然後排序將花費盡可能多的時間來讀取每一行,並只寫入我想要的數據庫? – kitenski 2010-07-22 13:46:07

+3

@kitenski:你試過了嗎?我的意思是,這只是大約10行代碼。 做19M順序,異步插入將比19M隨機選擇更快。 – Andreas 2010-07-22 14:23:29

3

不要試圖發明車輪,它已經完成。使用數據庫搜索文件的內容。您可以將該文件裝載到數據庫中的臨時表中,並使用索引查詢數據以便快速訪問(如果它們增加了值)。大多數(如果不是全部)數據庫都有導入/加載工具,可以相對較快地將文件導入數據庫。

+0

確實讀取每一行並寫入數據庫,然後排序將花費盡可能多的時間來讀取每一行,並只寫入我想要的數據庫? – kitenski 2010-07-22 13:55:15

+0

不讀取每一行並寫入數據庫,但利用大多數數據庫一次性批量加載文件的工具。之後,您可以選擇添加任何所需的索引,最後通過選擇/插入到數據庫表中來搜索您關心的數據。 – Kuberchaun 2011-12-12 02:21:55

0

數據庫是爲了處理大量數據而構建和設計的,PHP不是。您需要重新評估您如何存儲數據。

我將轉儲所有記錄到數據庫中,然後刪除你不需要的記錄。完成之後,您可以隨時隨地複製這些記錄。

2

如果數據庫設計不正確,數據庫上的19M行會減慢速度。如果分區正確,您仍然可以使用文本文件。基於某些參數重新創建多個較小的文件,以適當的排序方式存儲可能會奏效。

反正PHP不是文件IO和處理最好的語言,它比Java更慢了這個任務,而普通的老式C將是最快的工作之一。 PHP應該限制爲生成動態Web輸出,而核心處理應該使用Java/C。理想情況下,它應該是生成輸出的Java/C服務,以及使用該提要生成HTML輸出的PHP。

1

你試過剖析代碼,看看它是花費了大量的時間?這應該始終是您嘗試診斷性能問題時的第一步。

0

正如其他人所提到的,費用可能在您的數據庫查詢。從文件加載一批記錄(而不是一次一個)並執行一個查詢來檢查多個記錄可能會更快。在一個時間匹配的美元貨幣和店面成陣列,並執行類似的查詢

例如,負載1000記錄:

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

這將返回的那些在記錄的列表數據庫。或者,您可以將sql更改爲not in以獲取不在數據庫中的那些記錄的列表。

1

用sed和/或awk預處理?