CAT | perl
Вышла новая версия DBIx::Class::Schema::Loader с множеством изменений. Одно из этих изменений – генерация POD-документации для автоматически созданных классов. Пользователи PostgreSQL получат ещё одну вкусняшку – все комментарии к их таблицам и столбцам автоматически переедут в документацию. Не буду показывать на автора этого патча пальцем, так как это неприлично.
И второе. Test::Pod::Coverage::Permissive. Принцип работы такой же, как и у Test::Pod::Coverage, только тесты валятся лишь в том случае, если появилась ещё одна незадокументированная фунция.
Т.е. при первом запуске у вас тесты пройдут в любом случае. Задокументируете функцию — тесты пройдут. Напишете ещё одну незадокументированную функцию — обвалятся.
Это очень удобно, когда есть незадокументированный проект, который хочется дальше вести с документацией.
К чему это я — пользуйтесь и пишите баги.
Странно, что этого до сих пор никто не написал: App::Pm2Port
Создаёт порт из перлового модуля и отправляет его разработчикам FreeBSD.
Как работать:
pm2port CSS::Croco
Тестируем и находим баги.
Moose – это альтернативная объектная система для Perl 5. Она прячет от вас хитрые манипуляции с хэшами и “благословление” объектов и превращает Perl в язык с хорошим ООП.
(more…)
Все мы привыкли работать с базой в стиле:
- выполнить запрос
- дождаться ответа
- продолжить выполнение
Но пока работает длинный запрос, мы в приложении можем выполнить что-то полезное. Не простаивать же процессорному времени.
Для PostgreSQL в DBD::Pg есть некоторое подобие асинхронности. И иногда оно таки нам помогает.
Вы можете продолжить выполнять приложение, не дожидаясь выполнения запроса. Включается это параметром pg_async к prepare-запросу:
use strict; use warnings; use Time::HiRes 'sleep'; use DBD::Pg ':async'; my $dbh = DBI->connect('dbi:Pg:dbname=postgres', 'postgres', '', {AutoCommit=>0,RaiseError=>1}); ## Запустить длинный запрос my $sth = $dbh->prepare("SELECT pg_sleep(5)", {pg_async => PG_ASYNC}); $sth->execute(5); ## Пока работает, мы можем что-то сделать print "Your query is processing. Thanks for waiting\n"; check_on_the_kids(); while (!$dbh->pg_ready) { check_on_the_kids(); ## и подождём чуть-чуть sleep 0.1; } print "The query has finished. Gathering results\n"; my $result = $sth->pg_result; print "Result: $result\n"; my $info = $sth->fetchall_arrayref();
Для pg_async есть три константы:
- PG_ASYNC – выполнение запроса в асинхронном режиме
- PG_OLDQUERY_CANCEL – если в этот момент работал предыдущий запроса, то он отменяется
- PG_OLDQUERY_WAIT – блокируемся для ожидания предыдущего запроса и только потом начинаем выполнять новый
Так же есть три вспомогательных метода -
pg_cancel – отменить запрос. Реально открывается ещё одно соединение, в котором посылается SELECT pg_cancel_backend(?);
pg_ready – возвращает true, если запрос выполнился.
pg_result – блокируется до момента выполнения запроса, после чего возвращает то же, что и ->execute в стандартном режиме.
Из минусов – нельзя установить callback на момент исполнения запроса. Нужно постоянно проверять.
Так же в один момент времени в одном соединением можно выполнять только один запрос. Но что мешает открыть десяток соединений и по очереди посылать в них запросы?)
Попробую рассказать о применениях этой технологии:
- тяжёлые запросы + сложная логика. Равномерно загружаем свой сервер и сервер БД.
while (){ my $foo = compute_foo();#тяжёлая функция #блокируемся до тех пор, пока не выполнится предыдущий $dbh->do('UPDATE stats SET foo=foo+1', { pg_async => PG_ASYNC + PG_OLDQUERY_WAIT }); }
- работа с несколькими серверами БД
$first_dbh->do('DELETE FROM old_data', { pg_async => PG_ASYNC }); $second_dbh->do('UPDATE new_data SET status=0', { pg_async => PG_ASYNC })
- таймауты. вы можете убить запрос по таймауту, если он ещё не отработал
- конкуррентные запросы. посылаем один и тот же запрос двум серверам и отдаём данные с того сервера, который ответил быстрее.
- запросы, результат выполнения которых вам абсолютно безразличен
8
Профилирование SQL-запросов в DBI
Comments | Posted by Андрей Костенко in Uncategorized, perl
Как недавно оказалось, у DBI есть отличный профайлер. Включается он очень просто.
DBI_PROFILE=1 perl test.pl DBI::Profile: 27.088730s 58.89% (52900 calls) test.pl @ 2009-07-08 23:08:39
Как видите, он краток. А кратк. сестр. тал. Он показывает, стоит ли нам вообще оптимизировать SQL.
он говорит, что на базу потрачено 60% времени.
Если нужно оптимизировать базу, то запускаем скрипт с DBI_PROFILE=2
Тогда нам покажется подробный отчёт о времени, затраченном на каждый тип запроса.
Сегодня таки вышел Catamoose. А если простыми словами – Catalyst версии 5.08
Изменений просто дохрена:
- Первое и главное. Catalyst переписали на Moose. Теперь он будет есть не 80Мб, а 200Мб (:
- Избавились к чертям от тормоза NEXT, который ещё и работает через задницу
- Проапгрейдили Catalyst::Log, поправили баги и…
- всё
Обещаю, что если вы не полный распиздяй, и не вставляли костылей в сам Catalyst, то переезд на Catamoose больше минуты не займёт. А вот размер проекта в памяти вырос на 19Мб.
Простейший трейс включается переменной окружения DBIC_TRACE=1. Сейчас каждый запрос будет выводиться на STDERR перед выполнением.
Но что, если нам его недостаточно? Посмотрим, что нам даёт DBIx::Class. А даёт он нам класс DBIx::Class::Storage::Statistics.
Методы этого класса вызываются до и после каждого запроса, либо транзакции.
Попробуем после каждого запроса выводить время, которое он исполнялся. Это описано в DBIx::Class::Manual::Cookbook.
Добавляем схему:
__PACKAGE__->storage->debugobj(new My::Profiler()); __PACKAGE__->storage->debug(1);
И создаём модуль:
package My::Profiler; use strict; use base 'DBIx::Class::Storage::Statistics'; use Time::HiRes qw(time); my $start; sub query_start { my $self = shift(); my $sql = shift(); my $params = @_; $self->print("Executing $sql: ".join(', ', @params)."\n"); $start = time(); } sub query_end { my $self = shift(); my $sql = shift(); my @params = @_; my $elapsed = sprintf("%0.4f", time() - $start); $self->print("Execution took $elapsed seconds.\n"); $start = undef; } 1;
Отлично. Сейчас после каждого запроса пишется время выполнения. Если мы в My::Profile::print мы заменим print на carp, то после каждого SQL-запроса мы получим место его выполнения.
Но время выполнения запроса – это средняя температура по больнице, потому что может быть много быстрых запросов. Хотелось бы получить более красивую статистику. И она есть – DBIx::Class::QueryLog
Этот модуль сохраняет статистику по каждому выполненному запросу, группирует одинаковые запросы и сортирует по суммарному времени выполнения. Как им пользоваться – написано в документации. Свою задачу – ткнуть Вас носом в интересную фичу DBIx::Class – я выполнил.
Удачной Вам разработки.
Сегодня утром получил такое интересное письмо:
Привет! Это не спам
![]()
Я включил вас в список русских CPAN-авторов (Acme::CPANAuthors::Russian), т.к. вы очень похоже на русских )))
Если я ошибся и вы не хотите находится в этом списке, дайте мне знать.Спасибо!
use Perl or die;
Так приятно видеть в этом списке аццкое количество сотрудников Рамблера
use feature 'say'; say scalar(localtime(1234567890))
Sat Feb 14 02:31:30 2009
Расскажу вам про очень полезную вешь. Которую я даже сам редко использую. Прочёл я о ней в книге Стива Макконнела “Совершенный код”. Это Библия программиста. Советую прочесть всем.
Псевдокод
Когда вам нужно создать метод, не нужно торопиться и писать кучу кода. Попробуйте начать работать по такой схеме:
(more…)
