убить MySQL запрос в Perl - PullRequest
       4

убить MySQL запрос в Perl

2 голосов
/ 26 декабря 2010

У меня есть Perl-скрипт, в котором я создаю таблицу из существующих баз данных MySQL.У меня есть сотни баз данных, и таблицы в каждой базе данных содержат миллионы записей, из-за чего иногда запрос занимает часы из-за проблем с индексацией, а иногда у меня заканчивается свободное место на диске из-за неправильных объединений.Есть ли способ, которым я могу убить запрос в том же скрипте, отслеживая потребление памяти и время выполнения?

PS Я использую модуль DBI в perl для интерфейса mysql

Ответы [ 3 ]

2 голосов
/ 02 марта 2011

Я использовал команду KILL QUERY, как описано в http://www.perlmonks.org/?node_id=885620

Это код из моего скрипта

eval {
    eval { # Time out and interrupt work
        my $TimeOut=Sys::SigAction::set_sig_handler('ALRM',sub {
            $dbh->clone()->do("KILL QUERY ".$dbh->{"mysql_thread_id"});
            die "TIMEOUT\n";
        });
        #Set alarm
        alarm($seconds);
        $sth->execute();
        # Clear alarm
        #alarm(0);
    };
    # Prevent race condition
    alarm(0);
    die "$@" if $@;
};

Этот код убивает запрос, а также удаляет все временные таблицы

1 голос
/ 26 сентября 2013

Обратите внимание, что вы не можете завершить запрос, используя тот же обработчик соединения, если у вас есть запрос, который завис из-за блокировки таблицы. Вы должны открыть другое соединение с тем же пользователем и получите этот идентификатор потока.

Конечно, вы должны хранить в хэше список идентификаторов открытых в данный момент потоков.

Помните, что после того, как вы завершили идентификатор потока, остальная часть кода Perl будет выполнена ... на необъявленном обработчике.

1 голос
/ 26 декабря 2010

Что касается времени выполнения, вы используете alarm Функциональность Perl для тайм-аута.

Ваш дескриптор ALRM может либо die (см. Пример ниже), либо выполнить вызов DBI cancel (sub { $sth->cancel };)

Документация DBI на самом деле очень хорошо обсуждает это, а также примеры:

  eval {
    local $SIG{ALRM} = sub { die "TIMEOUT\n" }; # N.B. \n required
    eval {
      alarm($seconds);
      ... code to execute with timeout here (which may die) ...
    };
    # outer eval catches alarm that might fire JUST before this alarm(0)
    alarm(0);  # cancel alarm (if code ran fast)
    die "$@" if $@;
  };
  if ( $@ eq "TIMEOUT\n" ) { ... }
  elsif ($@) { ... } # some other error

Что касается слежения за памятью, вам просто нужен обработчик ALRM - вместо простого умирания / отмены - сначала проверяется потребление памяти вашим скриптом.

Я не буду вдаваться в подробности того, как измерить потребление памяти, поскольку это не связанный вопрос, на который, вероятно, уже был дан исчерпывающий ответ на SO, но вы можете использовать метод size() из Proc::ProcessTable , как описано в Perlmonks фрагмент Найти использование памяти программой Perl .

...