Friday, November 19, 2010

MySQL: обработка больших наборов данных

Большинство клиентских библиотек для работы с MySQL после выполнения запроса по умолчанию загружают весь result set в память. Это удобно: поскольку все строки уже находятся в памяти клиента, к ним можно обращаться в произвольном порядке. Также, доступно общее число строк. Недостаток - требования к памяти и ошибки "Out of memory" при достаточно больших наборах данных.

MySQL поддерживает и другой способ обработки результатов - построчно. В данном случае чтение строк происходит последовательно, напрямую с сервера. Этот способ позволяет работать с наборами данных, которые не поместились бы в RAM.

Первый способ использует для получения результатов запроса функцию MySQL API mysql_store_result, а второй - mysql_use_result. В перловом DBD::mysql использование mysql_use_result можно включить установкой одноименного атрибута dbh:
mysql_use_result

This attribute forces the driver to use mysql_use_result rather than mysql_store_result. The former is faster and less memory consuming, but tends to block other processes. (That's why mysql_store_result is the default.)

It is possible to set default value of the mysql_use_result attribute for $dbh using several ways:

- through DSN

$dbh= DBI->connect("DBI:mysql:test;mysql_use_result=1", "root", "");

- after creation of database handle

$dbh->{'mysql_use_result'}=0; #disable
$dbh->{'mysql_use_result'}=1; #enable


Недостатком этого метода является то, что пока не будут получены все данные из result set, в рамках соединения запрещено использовать новые запросы. Попытка выполнить новый запрос приводит к ошибке
Commands out of sync; you can't run this command now

Thursday, November 4, 2010

5 способов создания констант в Perl


  1. Прагма constant. Позволяет объявлять константы на этапе компиляции:
    use constant PI => 4 * atan2(1, 1);

    Этот способ весьма эффективен, но имеет несколько недостатков.

    • Такие "константы" не могут быть интерполированы в строках, что часто неудобно.

    • При использовании ссылки в качестве константы, возможно изменение данных по ссылке:
      use constant ARRAY => [ 1,2,3,4 ];
      print ARRAY->[1];
      ARRAY->[1] = " be changed";
      print ARRAY->[1];


    • Могут возникать проблемы, если константа используется в качестве ключа хэша, e.g. $hash{CONSTANT}, или перед оператором =>. В таких случаях надо давать дополнительные подсказки компилятору, e.g. $hash{+CONSTANT}.

    • Константы являются глобальными для модуля, в котором они определены.

    • Наконец, они могут быть банально переопределены с помощью той же прагмы.



  2. Модуль Readonly.
    use Readonly;
    Readonly my $PI => 4 * atan2(1, 1);

    Данный способ лишен всех недостатков, связанных с прагмой constant. Readonly правильно работает со ссылками, делая все данные по ссылке неизменяемыми. Однако он гораздо медленнее, особенно если не установлен модуль Readonly::XS. По словам автора, разница в производительности по сравнению c constant примерно в 20 раз.

    Несмотря на это, именно Readonly чаще всего используется для создания констант в Perl.

  3. Модуль Const::Fast.
    use Const::Fast;
    const my $PI => 4 * atan2(1, 1);

    Этот модуль похож на Readonly. Вместо tie он использует внутренний флаг SV, что делает его гораздо более быстрым.

  4. Еще один способ создания неизменяемых скалярных переменных - присвоение ссылки на константное значение (число, литерал или выражение) переменной типа typeglob:
    our $PI;
    *PI = (4 * atan2 1, 1);
    $PI = 3.14; # Modification of a read-only value attempted at ..

    Этот способ работает только для глобальных переменных.

  5. Начиная с версии Perl 5.8, для создания констант можно использовать встроенную функцию Internals::SvREADONLY():
    my $PI = 4 * atan2 1, 1;
    Internals::SvREADONLY($PI => 1);
    $PI = 3.14; # Modification of a read-only value attempted at ..

    Именно эту функцию внутренне используют модули Const::Fast и Data::Lock.