Perl с MySQL, ужасно медленно, как ускорить - PullRequest
1 голос
/ 03 марта 2012
unit
id fir_name sec_name
author
id name unit_id
author_paper
id author_id paper_id

Я хочу объединить авторов [«один и тот же автор» означает, что имена одинаковы, а имена юнитов их единиц одинаковы], и мне нужно изменить таблицу author_paper одновременно.

Вот что я делаю:

$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 
        }
    }
}

выбрать количество (*) от автора; # 240000 выбрать количество (отличное (имя)) от автора; # 7,7000 Это ужасно медленно !! Я запустил его в течение 5 часов, он просто удалил около 40000 дублированных имен. Как заставить его работать быстрее. Я с нетерпением жду вашего совета

Ответы [ 2 ]

8 голосов
/ 03 марта 2012

Вы не должны готовить второе выражение 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 
        }
    }
}

Это также должно ускорить процесс.1005 *

5 голосов
/ 03 марта 2012

В тот момент, когда я вижу запрос и цикл, я думаю, что у вас есть проблема с задержкой: вы запрашиваете набор значений, а затем перебираете набор, чтобы сделать что-то еще. Это ОЧЕНЬ много времени ожидания, если это означает, что для каждой строки в наборе выполняется обратное подключение к базе данных по сети.

Было бы лучше, если бы вы могли сделать это в одном запросе с использованием ОБНОВЛЕНИЯ и дополнительного выбора ИЛИ, если бы вы могли пакетировать эти запросы и выполнять их все в одном цикле.

Вы получите дополнительную скорость, если будете использовать индексы с умом. Каждый столбец в предложении WHERE должен иметь индекс. Каждый внешний ключ должен иметь индекс.

Я бы запустил EXPLAIN PLAN для ваших запросов и посмотрю, происходит ли TABLE SCAN. Если есть, вы должны правильно индексировать.

Интересно, придет ли вам на помощь правильно спроектированный JOIN?

240 000 строк в одной таблице и 77 000 в другой - не , что большой размер базы данных.

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