|
|||||||
Ouverture de sessionNavigationContactez-nousAdministration du site : RechercheSujets du forumSujets actifsNouveaux sujets:SyndicationSondageQuelle est la version de PostgreSQL la plus répandue sur vos serveurs ? 8.3 10% 8.2 42% 8.1 40% 8.0 2% 7.4 6% 7.3 ou antérieure 0% Nombre de votes: 48 |
Index inversé, en C| Index inversé, en CPar Guillaume Lelarge le 05/09/2007 - 18:33 Depuis la version 8i, Oracle implémente les index inversés. Voici une proposition d’implémentation équivalente pour PostgreSQL. Les index inversés permettent d’accélérer les recherches sur les motifs tels que « colonne LIKE '%chaîne' ». Dans un tel cas, PostgreSQL effectue un parcours séquentiel (ou « sequential scan ») de la table interrogée. Toutefois, il est possible d’émuler un index inverse au moyen d’une fonction de renversement de chaîne couplée à un index sur fonction. L'article précédent proposait l'implémentation d'un prototype en langage procédural PL/pgSQL, qui fait office ici de prototype. Cette implémentation a pour principal défaut d'être lente, pénalisant ainsi gravement les performances en écriture (INSERT et UPDATE). Ainsi, à chaque mise à jour, il est nécessaire de faire appel à la fonction Ainsi, l'implémentation en langage C se doit d'être à la fois plus rapide et surtout se doit de supporter les jeux de caractères multi-octets. C'est à partir de ce minuscule cahier des charges que nous allons construire notre fonction Pourquoi écrire une procédure stockée en CPourquoi s'embêter à prendre le temps d'écrire une procédure stockée en langage C alors qu'il est possible de faire la même chose en langage PL/pgSQL ?
Le gain significatif de vitesse ne sera pas évident pour les requêtes de sélection. En revanche, les écritures (surtout INSERT et UPDATE) peuvent être fortement pénalisées par le coût de la mise à jour d'un index fonctionnel. Bien que cela ne soit pas évident pour une opération unitaire, il sera parfaitement visible dans le cas d'une opération d'écriture en masse (chargement massif de données), ou tout simplement pour la création de l'index fonctionnel. Dans un tel cas, l'option d'une réécriture en langage C est à envisager très sérieusement. Implémentation et discussion techniqueLes possibilités d'extension de PostgreSQL s’appuient sur les mécanismes de chargement dynamique de bibliothèque du système d’exploitation. L’interface de programmation est relativement simple, à condition d’en connaître certaines clés. Structure du projetLe projet est articulé autour de différents fichiers, qui seront tous placés dans un répertoire dédié :
Fichiers annexesAvant toute chose, il faut disposer d’un fichier « Makefile » de construction du module externe :
MODULES = reverse Le Makefile utilise ici l’outil PGXS qui propose un fichier Makefile prédéfini, à l’instar des fichiers Makefile fournis par Oracle. Le fichier « reverse.sql.in » qui sert de modèle à la création du fichier d'installation de l'extension «
-- Déclaration de la fonction reverse en tant que module C Le script « reverse.sql » sera exécuté par un utilisateur PostgreSQL ayant le rôle d’administrateur, les fonctions C étant considérées comme non-sûres et donc de la responsabilité de l’administrateur. Un script de désinstallation « uninstall_reverse.sql » est également prévu, ça fait toujours plaisir :
SET search_path = public; Un peu de techniqueLa lecture de la page « Fonctions en langage C » permet d’obtenir les informations nécessaires au développement d’une fonction C, voir la documentation « Fonctions en langage C ». Cependant la lecture des fichiers d’en-têtes permet d’apporter un éclairage supplémentaire sur certaines structures de données. Traitement des chaînes de caractères avec PostgreSQLSous PostgreSQL, les chaînes de caractères ne sont pas délimitées par un caractère nul « Voici sa définition, obtenu dans le fichier d'en-tête c.h, à la ligne 409 :
struct varlena Ainsi, l'entier Quelques macros permettent de manipuler facilement cette structure.
Ainsi, pour obtenir la longueur en octets de la données, on utilisera Support des jeux de caractères multi-octetsL'implémentation proposée supporte les jeux de caractères multi-octets, comme l'UTF8 (ou Unicode) et les jeux de caractères asiatiques, qui représente certains caractères sous la forme d'une séquence de deux octets ou plus (voir référence). PostgreSQL met à disposition des fonctions utiles pour manipuler les chaînes de caractères, peu importe l'encodage, notamment Les conventions d'appelIl existe deux conventions d'appel de fonctions externes :
La convention d'appel version 1 sera utilisée dans le but de donner d'entrée de jeu de bonnes habitudes. La complexité de cette convention est masquée par une batterie de macros qui rendent son utilisation tout aussi simple, voire encore plus simple que la version 0, notamment pour le passage d'arguments. Implémentation en langage CLe source C est structuré en quatre parties :
Voici ci-après, le code source en langage C de la fonction reverse.
/* ConstructionLa construction de l'extension PostgreSQL est réalisée en invoquant
tom@clementina:~/src/reverse$ make Si tout s'est bien passé, l'installation sera finalisée en exécutant la commande
tom@clementina:~/src/reverse$ sudo make install Les fichiers produits seront ainsi installés dans le répertoire d'installation de PostgreSQL. Il est toutefois possible de les positionner ailleurs, à condition d'adapter le fichier « Utilisation et performancesVérification de bon fonctionnementDans un premier temps, on crée la fonction via l'outil
test=# \i reverse.sql On vérifie que la fonction répond correctement :
test=# SHOW client_encoding; Ok, ça marche, y compris avec les chaînes encodées en UTF-8 ! Petit test de performanceCe test a été réalisé par depesz, qui m'a aimablement autorisé a le réutiliser dans le cadre de cet article. Petit aperçu du jeu de test :
test=# SELECT count(*), Maintenant, voici une petite comparaison des trois implémentations, à savoir le prototype en PL/pgSQL, la version PL/perl de depesz et la version C. On oppose à ces trois tests un parcours de la table via la fonction d'agrégat count(), permettant ainsi de mesurer l'overhead due à chaque implémentation de la fonction Simple comptage (count)Voici l'ordre SQL utilisé pour réaliser ce test :
test=# EXPLAIN ANALYZE Et voici les temps de réponse obtenus : Prototype PL/pgSQL
test=# EXPLAIN ANALYZE Exécution #1 : 55269.941 ms Version PL/perl
test=# EXPLAIN ANALYZE Exécution #1 : 4088.625 ms Version C
test=# EXPLAIN ANALYZE Exécution #1 : 1596.176 ms Synthèse du test de performanceVoici un graphe faisant la synthèse des moyennes des temps de réponse : Le graphe suivant permet de mieux se rendre compte de l'overhead induie par l'implémentation PL/perl et l'implémentation C. Chose très intéressante : l'overhead pour renverser ~320000 enregistrements est de seulement 300ms, ce qui est bien entendu excellent et laisse présager de très bonnes performances quant au coût de la mise à jour d'un index fonctionnel. Ainsi, comme cela pouvait être aisément imaginé, la version C est la plus rapide, suivie par la version PL/Perl. La version PL/pgSQL se traîne lamentablement derrière, ce qui justifie complètement la réécriture de la procédure stockée en C. NotesCette fonction a été testé sur une base en PostgreSQL 8.0, 8.2 et 8.3devel (merci à depesz). Je regrette de ne pas avoir pu aller un peu plus loin pour le précédent article, des impératifs de place m'ayant obligé à aller à l'essentiel sans montrer les différents plans d'exécution. Heureusement, l'article de hubert depesz lubaczewski montre tous les aspects que j'ai négligé, malheureusement c'est en anglais. RéférencesDe plus amples précisions sont également disponibles en langue anglaise sur les sites Internet suivant :
RemerciementsJe remercie vivement les personnes suivantes :
Article écrit par Thomas Reiss, publié sur postgresqlfr.org avec sa permission. Vous pouvez le retrouver sur son blog où il parle encore de PostgreSQL (et d'autres choses :-) ). Merci beaucoup.
|
||||||
© PostgreSQLFr, tous droits rĂ©servĂ©s.
Site déclaré à la CNIL sous le numéro 1074678, conformément à la Loi en vigueur.