2012-03-03 14 views
1
unit 
id fir_name sec_name 
author 
id name unit_id 
author_paper 
id author_id paper_id 

著者を統一したい[同じ著者は名前が同じであり、そのユニットのfir_namesが同じであることを意味する]、author_paperテーブルを同じ時間。ここでPerlがmysqlを使っている、ひどく遅い、加速する方法

は私が何をすべきかです:

$conn->do('create index author_name on author (name)'); 
my $sqr = $conn->prepare("select name from author group by name having count(*) > 1"); 
$sqr->execute(); 
while(my @row = $sqr->fetchrow_array()) { 
    my $dup_name = $row[0]; 
    $dup_name = formatHtml($dup_name); 
    my $sqr2 = $conn->prepare("select id, unit_id from author where name = '$dup_name'"); 
    $sqr2->execute(); 

    my %fir_name_hash =(); 
    while(my @row2 = $sqr2->fetchrow_array()) { 
     my $author_id = $row2[0]; 
     my $unit_id = $row2[1]; 
     my $fir_name = getFirNameInUnit($conn, $unit_id); 
     if (not exists $fir_name_hash{$fir_name}) { 
      $fir_name_hash{$fir_name} = []; #anonymous arr reference 
     } 
     $x = $fir_name_hash{$fir_name}; 
     push @$x, $author_id; 
    } 

    while(my ($fir_name, $author_id_arr) = each(%fir_name_hash)) { 
     my $count = scalar @$author_id_arr; 
     if ($count == 1) {next;} 
     my $author_id = $author_id_arr->[0]; 
     for ($i = 1; $i < $count; $i++) { 
      #print "$author_id_arr->[$i] => $author_id\n"; 
      unifyAuthorAndAuthorPaperTable($conn, $author_id, $author_id_arr->[$i]); #just delete in author table, and update in author_paper table 
     } 
    } 
} 

SELECT COUNT(*)の著者から。 #240,000 著者からの選択回数(distinct(name))。 #7,7000 それはとても遅いです!私は5時間走りました、それはちょうど約4,0000ダップの名前を削除しました。 あなたのアドバイスを熱望しています

+0

空でないテーブルにインデックスを作成するには、しばらく時間がかかることがあります。 240k行は大きなテーブルではありません。 – Kamil

+0

[perl with mysql、恐ろしく遅い、それを修正する方法](http://stackoverflow.com/questions/9533333/perl-with-mysql-terribly-slow-how-to-fix-it) – Toto

答えて

8

あなたは、ループ内の第2のSQLステートメントを準備するべきではありません、あなたは?プレースホルダを使用するときには、準備の実際の利用を行うことができます。

$conn->do('create index author_name on author (name)'); 

my $sqr = $conn->prepare('select name from author group by name having count(*) > 1'); 

# ? is the placeholder and the database driver knows if its an integer or a string and 
# quotes the input if needed. 
my $sqr2 = $conn->prepare('select id, unit_id from author where name = ?'); 

$sqr->execute(); 
while(my @row = $sqr->fetchrow_array()) { 
    my $dup_name = $row[0]; 
    $dup_name = formatHtml($dup_name); 

    # Now you can reuse the prepared handle with different input 
    $sqr2->execute($dup_name); 

    my %fir_name_hash =(); 
    while(my @row2 = $sqr2->fetchrow_array()) { 
     my $author_id = $row2[0]; 
     my $unit_id = $row2[1]; 
     my $fir_name = getFirNameInUnit($conn, $unit_id); 
     if (not exists $fir_name_hash{$fir_name}) { 
      $fir_name_hash{$fir_name} = []; #anonymous arr reference 
     } 
     $x = $fir_name_hash{$fir_name}; 
     push @$x, $author_id; 
    } 

    while(my ($fir_name, $author_id_arr) = each(%fir_name_hash)) { 
     my $count = scalar @$author_id_arr; 
     if ($count == 1) {next;} 
     my $author_id = $author_id_arr->[0]; 
     for ($i = 1; $i < $count; $i++) { 
      #print "$author_id_arr->[$i] => $author_id\n"; 
      unifyAuthorAndAuthorPaperTable($conn, $author_id, $author_id_arr->[$i]); #just delete in author table, and update in author_paper table 
     } 
    } 
} 

これは、同様に物事をスピードアップする必要があります。

+0

これは多くのスピードアップを行います。また、[リンク](http://www.mysqlfaqs.net/mysql-faqs/General-Questions/What-is-prepared-statement-in-MySQL) – lhdgriver

4

私はクエリとループが表示される瞬間、待ち時間の問題があると思います:値のセットを取得してセットを反復するクエリ何か他のことをする。これは、セット内の各行のデータベースへのネットワークラウンドトリップを意味する場合は、多くのレイテンシです。

UPDATEとサブセレクトを使用して1つのクエリで実行できる場合、またはそれらの要求をバッチして1回の往復ですべて実行することができればよいでしょう。

インデックスを賢明に使用すると、スピードアップにつながります。 WHERE句の各列にはインデックスが必要です。すべての外部キーにはインデックスが必要です。

私はあなたのクエリでEXPLAIN PLANを実行し、TABLE SCANが実行されているかどうかを確認します。存在する場合は、適切にインデックスを作成する必要があります。

正しく設計されたJOINがあなたの救助に来るのだろうかと思いますか?

1つのテーブルでは240,000行、別のテーブルでは77,000がデータベースではありません。

+0

あなたの可能な複製そうです。私はそのループも好きではありません。彼はSQLを使用していない、多分複雑なクエリを書く方法を知らない。 – Kamil

関連する問題