Une étrange limitation de PostGreSQL

Voici une bien étrangère limitation que nous offre l’optimiseur de PostgreSQL. Il n’est en effet pas capable de faire une jointure externe bilatérale lorsque le prédicat de jointure n’est pas « sargeable »…

La jointure externe est assez peu utilisée, mais elle se conçoit bien, lorsque l’on veut pas exemple faire du rapprochement de données; En voici un exemple :
Soit deux tables contenant des clients pour l’un et des prospects pour l’autre. On à collecté comme information le n° de SIREN et le nom d’enseigne.
Mais le nom peut être mal orthographié comme le SIREN peut être incorrect. Le but étant de joindre ces données avec le maximum de « chances »…

Voici le modèle de la base :

CREATE TABLE T_CLIENT_CLI
(CLI_ID       INT PRIMARY KEY,
 CLI_SIREN    CHAR(9) NOT NULL UNIQUE,
 CLI_ENSEIGNE VARCHAR(16) NOT NULL);

CREATE TABLE T_PROSPECT_PSP
(PSP_ID       INT PRIMARY KEY,
 PSP_SIREN    CHAR(9) NOT NULL UNIQUE,
 PSP_ENSEIGNE VARCHAR(16) NOT NULL);

Et quelques données de test :

INSERT INTO T_CLIENT_CLI VALUES
(1, '123456789', 'IBM'),
(2, '111111111', 'Microsoft'),
(3, '999555111', 'SAP');

INSERT INTO T_PROSPECT_PSP VALUES
(101, '123456789', 'IBM'),
(102, '555555555', 'Microsoft'),
(103, '777777777', 'Amazon'),
(104, '444444444', 'Google');

Nous voyons que le code SIREN de Microsoft ne se recoupe pas sur les deux tables… Cepandant nous voulons toutes les données des deux tables avec jointure sur le code SIREN ou à défaut sur le nom.
La requête suivante correspond à cette demande :

SELECT *
FROM   T_CLIENT_CLI AS C
       FULL OUTER JOIN T_PROSPECT_PSP AS P
            ON C.CLI_SIREN = P.PSP_SIREN
            OR C.CLI_ENSEIGNE = P.PSP_ENSEIGNE

Voici ce qu’elle donne sous MS SQL Server :

CLI_ID      CLI_SIREN CLI_ENSEIGNE     PSP_ID      PSP_SIREN PSP_ENSEIGNE
----------- --------- ---------------- ----------- --------- ----------------
1           123456789 IBM              101         123456789 IBM
2           111111111 Microsoft        102         555555555 Microsoft
3           999555111 SAP              NULL        NULL      NULL
NULL        NULL      NULL             103         777777777 Amazon
NULL        NULL      NULL             104         444444444 Google

Hélas, cette requête ne passe pas sous aucune version de PostGreSQL. le message est le suivant :

ERREUR:  FULL JOIN est supporté seulement avec les conditions de jointures MERGE et de
jointures HASH JOIN
********** Erreur **********
État SQL :0A000


L’explication est la suivante :

PostGreSQL veut impérativement que la jointure soir « sargeable », c’est à dire utiliser une technique de jointure avec algorithme MERGE (fusion d’un tri resultant d’index) ou algorithme HASH (donc index avec clef de hachage)… Or, avec un « ou » (OR) dans la clause On de la jointure il n’y a pas de « sargeabilité » possible !
Si vous ne prenez pas en compte la dernière ligne (OR OR C.CLI_ENSEIGNE = P.PSP_ENSEIGNE) alors la requête s’exécute. Si vous mettez AND à la place de OR, ça passe. mais tout ceci ne donne pas le même résultat
En fait, c’est une limitation assez curieuse de l’optimiseur de PostGreSQL qui interdit le FULL OUTER JOIN dans certains cas…

Évidemment, cela constitue à l’évidence un bug…

PS : version PG testée 9.1.2 et 9.3.4

Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES
Expert  S.G.B.D  relationnelles   et   langage  S.Q.L
Moste  Valuable  Professionnal  Microsoft  SQL Server
Société SQLspot  :  modélisation, conseil, formation,
optimisation,  audit,  tuning,  administration  SGBDR
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.

L’entreprise SQL Spot
Le site web sur le SQL et les SGBDR

MVP Microsoft SQL Server

Laisser un commentaire