Page suivante   Page précédente   Table des matières  

3. Grands Objets et Perl DBI

Mark Nielsen

Si ce document changeait, la version originale peut se trouver sur http://genericbooks.com/Literature/Articles/2.

3.1 Ressources

Je présume que vous avez installé DBI et DBD::Pg avec Perl.

  1. man DBI
  2. man DBD::Pg
  3. ftp://ftp.perl.com/CPAN/modules/by-category/07_Database_Interfaces/
  4. Une requête comportant "large" et "dbi" sur un des forums postgresql.
  5. http://www.postgresql.org/doxlist.html -- Un chapitre sur les Grands Objets dans le Guide du Programmeur pour PostgreSQL.
  6. http://www.postgresql.org/docs/programmer/largeobjects3386.htm Deux exemples utilisant psql qui expliquent comment utiliser les Grands Objets.

3.2 Introduction

Je travaille pour ZING (ZING Is Not GNU). Nous vendons et distribuons de la documentation et des livres sur le libre. Eh bien, en plus de vendre des livres bon marché, nous souhaitons aussi que l'on puisse télécharger les livres. Ceci pose problème quand vous souhaitez prendre des méga-octets de données pour les mettre dans une base de données. J'ai déjà conçu des programmes destinés à déposer de grandes quantités de données dans des bases de données, mais pas plus de 100k de données par transaction. Ce fut la première fois que j'ai eu besoin de mettre des fichiers vraiment grands dans une base de données. Mon plus gros problème fut que ceci n'est pas très bien documenté quand vous utilisez Perl. Aussi, je n'avais jamais eu besoin d'utiliser les Grands Objets avec PostgreSQL. Je me suis servi d'autres serveurs de base de données pour les Grands Objets, mais pas de PostgreSQL.

Que sont les Grands Objets? Les Grands Objets sont des choses (des données binaires ou du texte) qui ne peuvent être stockées dans un champ normal d'une table. Par exemple, un fichier de 100 méga-octets ne peut vraiment pas rentrer dans un champ d'une table.

Quelles sont les technologies dont je me suis servi? La distribution RedHat de Linux, postgresql-6.5.3, Perl 5 (avec DBI, DBD::Pg et Pg) ainsi que apache_1.3.9.

D'une manière générale, comment peut-on utiliser les Grands Objets avec PostgreSQL ? Vous pouvez sauver des Grands Objets tels que des "fichiers" là où le serveur de base de données vous laissera entrer un fichier et vous donnera un nombre en retour et, quand vous voudrez récupérer les données, vous utiliserez ce nombre pour exporter vos données dans un fichier temporaire sur votre disque dur.

C'est plutôt bizarre. Pour extraire un Grand Objet, cela prend plus ou moins deux étapes. D'abord, vous copiez les données dans un fichier sur votre ordinateur: vous pouvez alors le lire. Le problème, de mon point de vue, est que les données sont normalement lues une fois. Là, elles sont lues deux fois: d'abord pour créer le fichier puis pour le lire. Il n'y a pas de moyen de contourner cela (pour autant que je sache) mais je suis novice dans le domaine des Grands Objets dans PostgreSQL (bien que les ayant utilisés dans d'autres serveurs de bases de données auparavant). Aussi y a-t-il peut-être de meilleures façons de faire.

3.3 Utilisation de Perl DBI

PERL est un langage de programmation utilisé par de nombreux professionnels du web et des bases de données. Cela a pris deux ans mais, maintenant, les gens reconnaissent finalement que les logiciels libres et ouverts, comme:

peuvent être utilisés par des sociétés commerciales comme une alternative aux langages de programmation commerciaux boursouflés, inefficaces et instables (pour lesquels la plupart du temps vous n'avez pas le code source et ne pouvez donc jamais être sûr que ce que vous utilisez fasse tout ce qu'il prétend faire -- je pense à une société en particulier). En tant que prestataire, j'ai noté une explosion des travaux en Perl (cela me plaît grandement de voir la montée de logiciels à l'éthique pure) et, donc, je suis sûr que ceci sera utile à d'autres prestataires par ci par là qui préféreront utiliser PostgreSQL plutôt que d'autres possibilités. Perl DBI est une interface générique pour base de données servant à tous les fichiers ou serveurs de bases de données. Pour vous connecter à une base de données spécifique, vous aurez aussi besoin d'un driver Perl DBD. Par exemple, pour me connecter à PostgreSQL, j'utilise Perl DBI et Perl DBD:Pg. Voici un court exemple de ce que je fais pour afficher les prénoms et les noms d'une base de données PostgreSQL en utilisant la table "people".


#!/usr/bin/perl

use DBI;
use vars qw($dbh);
    ### zing est la base de données à laquelle je me connecte
$dbh ||= DBI->connect("dbi:Pg:dbname=zing");

my $Command = "select first_name,last_name from people 
          sort by last_name,first_name";

my $sth = $dbh->prepare($Command);
my $Result = $sth->execute;

while (my @row_ary  = $sth->fetchrow_array)
  {print " $row_ary[0] $row_ary[1]\n";}

Le problème avec PERL DBI est que l'interface pour les Grands Objets n'est pas encore bien au point et que vous devez utiliser un pilote DBD spécifique à chaque type de base de données. Le problème avec DBD::Pg est que les Grands Objets ne sont pas très bien documentés et que cela m'a pris beaucoup de temps à fouiller dans les forums de news pour trouver la réponse que je cherchais. Par la suite, je me suis aussi arrangé pour trouver cet article sur les Grands Objets.

3.4 Utilisation des Grands Objets et de Perl

AVERTISSEMENT : la raison pour laquelle les fichiers temporaires sont en fait une bonne solution, c'est que, pour les grands fichiers, si vous lisez toutes les données en mémoire en une seule fois et que Perl tourne sous Apache, mod_perl utilisera beaucoup de mémoire système et ne la rendra pas (même si Perl réutilisera lui-même cette mémoire). Imaginez que vous ayez 10 personnes chargeant des fichiers de 10 méga-octets et que votre script Perl charge les fichiers en mémoire avant de les publier (au lieu de les publier ligne par ligne). Apache utilisera 100 méga-octets de mémoire système (en fait c'est Perl qui les aura) et ne vous les rendra pas. Ceci peut être mauvais. Dans d'autres serveurs de bases de données utilisant les Grands Objets, je peux charger les données directement en mémoire. Je ne conseille pas de le faire avec des fichiers vraiment grands de toute façon. Lisez ce guide de performances pour plus d'information.

Bien, comment importer et exporter des Grands Objets avec PostgreSQL ? L'exemple suivant vient directement de la documentation PostgreSQL. Cet exemple utilise le programme psql.


CREATE TABLE image (
    name            text,
    raster          oid
);

INSERT INTO image (name, raster)
    VALUES ('beautiful image', lo_import('/etc/motd'));

SELECT lo_export(image.raster, "/tmp/motd") from image
    WHERE name = 'beautiful image';

Maintenant, nous avons besoin de convertir ceci en perl. Voici un script perl qui fera exactement la même chose


#!/usr/bin/perl

use vars qw($dbh);
$dbh ||= DBI->connect("dbi:Pg:dbname=zing");

my $Command = "INSERT INTO image (name, raster)
            VALUES ('beautiful image', lo_import('/etc/motd'));";

my $sth = $dbh->prepare($Command);
$sth->execute();


$Command = "SELECT lo_export(image.raster, '/tmp/motd') from image
             WHERE name = 'beautiful image'";
$sth = $dbh->prepare($Command);
$sth->execute();

Ces deux exemples font la chose suivante: la première commande charge le fichier /etc/motd dans une table. La seconde commande prend les données de la table et les exporte dans un fichier appelé /tmp/motd. Si vous voulez obtenir l'oid des données dans la table et l'exporter dans une table, vous pouvez aussi faire ceci.


  ## Cette commande renvoie un numéro "oid" numérique
$Command = "SELECT raster from image WHERE name = 'beautiful image'";
$sth = $dbh->prepare($Command);
$sth->execute();
my @row_ary  = $sth->fetchrow_array;
my $Oid = $row_ary[0];

  ## Cette commande exporte les données avec l'oid dans un fichier
$Command = "SELECT lo_export($Oid, '/tmp/motd') from image";
$sth = $dbh->prepare($Command);
$sth->execute();

Pour des exemples réels, ZING à l'adresse http://www.genericbooks.com propose tous ces scripts Perl en accès pour tous. Cherchez des scripts qui montrent des documents qui sont extraits de la base de données. ZING a maintenant des scripts de configuration qui permettent aux gens de transférer ou télécharger des documents: vous devriez donc voir traîner des exemples réels sur le site web.

3.5 Utilisation du serveur de base de données avec un serveur web.

Bien, quels problèmes pouvez-vous rencontrer quand vous utilisez un serveur web pour importer/exporter les données d'un serveur de base de données ? Eh bien, le plus gros problème que j'ai vu était que si le serveur de base de données et le serveur web tournent sous deux comptes différents (comme "www" et "pgsql"), le serveur web et celui de base de données peuvent avoir des problèmes pour lire les fichiers temporaires de l'autre. Voici une liste de problèmes et leurs solutions.

Chez ZING, nous exportons les fichiers en fonction du pid du processus fils du serveur web. Quand le serveur web a besoin d'exporter un autre document, il confie le processus à un de ses fils, et si le fils a déjà exporté un document auparavant, il écrasera le précédent ce qui fait que nous ne finissons par par avoir des tonnes de fichiers exportés non tués. Puis, toutes les heures, nous parcourons le répertoire et tuons tout fichier existant depuis plus de 15 minutes. Ce n'est pas aussi élégant que je le souhaiterais mais ça marche très bien.

En général, c'est une mauvaise idée de laisser votre serveur web avoir le statut de super utilisateur ou que le serveur web et le serveur de base de données tournent avec le même nom d'utilisateur. Pour des raisons de sécurité, vous ne souhaitez pas que votre serveur web ait le pouvoir d'exploser le serveur de base de données.

3.6 Commentaires

Je n'aime pas vraiment la manière dont les Grands Objets sont manipulés dans PostgreSQL ou dans tout autre serveur de base de données que j'ai utilisé. Il devrait y avoir une manière de traiter l'importation et l'exportation des données à partir d'un serveur de base de données comme STDIN ou STDOUT où vous prenez le truc ligne par ligne et pas tout le fichu paquet à la fois. Je n'aime pas le fait que l'on ait à utiliser des fichiers intermédiaires pour arriver aux données. Ce serait bien de pouvoir choisir directement de mettre les données en mémoire ou de se servir de fichiers temporaires si les données sont trop grosses pour tenir en mémoire. Le CHOIX est le mot clé ici. Qu'est-ce que cela signifie ? Puisque PostgreSQL est le serveur de base de données libre le meilleur du moment, aidons les gens à s'en sortir en devenant développeur pour PostgreSQL ! Peut-être y a-t-il une façon de charger les Grands Objets en mémoire en se servant de PostgreSQL et, s'il y en a, écrivez une suite à cet article et prouvez que j'ai tort ! De fait, être capable d'accéder aux Grands Objets une ligne à la fois serait vraiment bien.

De toutes façons, j'essaierai de trouver de meilleures solutions aussi faites moi savoir si vous entendez parler de quelque chose de semblable.

Les Grands Objets ont toujours été une souffrance pour moi. J'ai toujours voulu utiliser les Grands Objets dans PostgreSQL. Maintenant que j'ai une raison, j'ai fini par y arriver. Heureusement cela épargnera des migraines à d'autres. Si ça vous a évité une migraine, donnez du temps ou de l'argent à ZING ou faites quelque chose de charitable pour une autre cause! Si chacun de nous le faisait un peu, cela aurait un large impact.

Mon prochain but est de manipuler les Grands Objets dans PostgreSQL en utilisant les langages de programmation PHP et Python. Après cela, je veux voir s'il y a une manière d'utiliser les Grands Objets sans être super utilisateur. Encore après, je veux comparer tout ceci à MySQL. Pour des raisons de licence et comme PostgreSQL a toujours été libre à 100% et ouvert, je préfère PostgreSQL à MySQL. Pourtant je veux les comparer et les mettre en compétition pour aider à rendre PostgreSQL meilleur. Récemment, MySQL a assoupli sa licence mais je vais continuer à coller à PostgreSQL parce qu'il ont toujours eu la meilleure licence.

Mark Nielsen travaille pour The Computer Underground comme réceptionniste et il est relieur de livres à ZING. Pendant ses heures de loisir, il effectue des tâches bénévoles comme écrire ces documents pour la Linux Gazette (et d'autres magazines).

Copyright 1999, Mark Nielsen. Paru dans le numéro 50 de la Linux Gazette de février 2000.

Traduction française de Daniel DETCHEBERRY.


Page suivante   Page précédente   Table des matières