2012-01-09 70 views
0

現在我有兩個散列哈希值,我通過解析一個日誌文件創建了1個哈希,我從SQL獲取了1個哈希。我需要比較它們以確定日誌文件中的記錄是否已經存在於數據庫中。現在我通過遍歷每個元素來比較它們:比較哈希散列的最佳方法是什麼?

foreach my $i(@record) 
{ 
    foreach my $a(@{$data}) 
    { 
     if ($i->{port} eq $a->{port} and $i->{name} eq $a->{name}) 
     { 
      print "match found $i->{name}, updating record in table\n"; 
     } 
     else 
     { 
      print "no match found for $tableDate $i->{port} $i->{owner} $i->{name} adding record to table\n"; 
      executeStatement("INSERT INTO client_usage (date, port, owner, name, emailed) VALUES (\'$tableDate\', \'$i->{port}\', \'$i->{owner}\', \'$i->{name}\', '0')"); 

     } 
    } 

} 

當然,隨着數據庫變大,這需要很長時間才能運行。有沒有更有效的方法來做到這一點?我可以直接比較密鑰嗎?

+1

這樣的聲音應該在SQL中解決,而不是perl。當然,有一種方法可以在SQL中「更新或插入」? – TLP 2012-01-09 16:36:51

回答

0

如何使用數據::差異:

use Data:Difference qw(data_diff); 

my @diff = data_diff(\%hash_a, \%hash_b); 

@diff = (
    { 'a' => 'value', 'path' => [ 'data' ] }, # exists in 'a' but not in 'b' 
    { 'b' => 'value', 'path' => [ 'data' ] }, # exists in 'b' not in 'a' 
); 
2

你有超過哈希散列更多。您有兩個列表,每個列表中的每個元素都包含散列哈希。因此,您必須將列表中的每個項目與另一個列表中的每個項目進行比較。你的算法的效率是O - 不是因爲它是哈希散列,而是因爲你將一個列表中的每一行與另一個列表中的每一行進行比較。

是否有可能通過您的列表,並將它們轉換爲由端口和名稱鍵入的哈希值?這樣,你通過每個列表一次來創建索引哈希,然後通過哈希一次來做比較。

my %record_hash; 
foreach my $record_item (@record) { 
    my $name = $record_item->{name}; 
    my $data = $record_item->{data} 
    my $record_hash{$name:$data} = \$record_item #Or something like this... 
} 

接下來,你會做同樣爲您數據列表:

例如,從記錄中創建哈希

my %data_hash; 
foreach my $data_item (@{$data}) { 
    my $name = $data_item->{name}; 
    my $data = $data_item->{data} 
    my $data_hash{$name:$data} = \$data_item #Or something like this... 
} 

現在,你可以通過你的新創建散列只是一次:

foreach my $key (keys %record_hash) { 
    if (exists $data_hash{$key}) { 
     print "match found $i->{name}, updating record in table\n"; 
    } 
    else { 
     print "no match found for $tableDate $i->{port} $i->{owner} $i->{name} adding record to table\n"; 
     executeStatement("INSERT INTO client_usage (date, port, owner, name, emailed) VALUES (\'$tableDate\', \'$i->{port}\', \'$i->{owner}\', \'$i->{name}\', '0')"); 

    } 
} 

假設你有100一個列表中有0個元素,另一個列表中有500個元素。您的原始算法將不得不循環500 * 1000次(50萬次)。通過創建索引散列,您必須循環2(500 + 1000)次(大約3000次)。

另一種可能性:既然您已經在使用SQL數據庫,那麼爲什麼不把它作爲SQL查詢呢。也就是說,不要獲取記錄。相反,通過您的數據,併爲每個數據項獲取記錄。如果記錄存在,則更新它。如果不是,則創建一個新的。這可能會更快,因爲你沒有把整個事情變成一個列表,以便把它變成一個哈希。

有一種方法可以直接對tie SQL databases進行哈希。這可能是一個好方法。

您使用的是Perl-DBI

+0

優秀的答案 – Richard 2012-01-10 09:40:16

+0

感謝您的回覆,這是非常豐富的。我可能會嘗試爲您建議的每條記錄創建一個散列。我也嘗試使用SQL命令,如IF EXISTS,正如你在第二種可能性中提到的那樣,但不能讓它們正常工作。我想過的另一個想法是嘗試使用通過解析日誌文件收集的數據創建臨時表,然後連接兩個表來查看哪些記錄存在,然後添加不存在的記錄。 – cottageDog 2012-01-10 14:43:25

+0

我最後在MySQL上使用存儲過程來根據記錄的存在插入或更新。 – cottageDog 2012-01-11 16:25:05

相關問題