Un cadeau empoisonné
Loptimiseur (planner) choisit pour vous le meilleur plan dexécution pour chaque requête en fonction de statistiques sur les données et autres informations. Il est libre de ses choix sauf si vous le contraignez à faire ce ce que vous voulez. Certains SGBD disposent pour cela de "hints", quon peut traduire par "indications" en français. Mais ce ne sont pas des indications, ce sont des directives données à loptimiseur : "PASSE PAR TEL INDEX !", "UTILISE DES BOUCLES IMBRIQUEES !" etc.
PostgreSQL ne dispose pas nativement dun tel système et ses développeurs se font donc régulièrement tarabuster à ce sujet. Ils ont bien raison de ne pas céder. Jutilise Oracle Database depuis très longtemps et jai souvent eu à résoudre des problème liés à des hints mal positionnés. Il y a tellement de moyens plus souples pour résoudre un problème de plan dexécution, à commencer par une adaptation des statistiques. Il est rarissime que les hints soient indispensables et fréquent quils détériorent les temps de réponse sur le long terme. Jonathan Lewis est sans doute le meilleur expert Oracle du CBO (cost based optimizer) et il est CONTRE le positionnement de hints dans le code applicatif. Par conséquent oubliez les ! Fin de larticle.
Oui mais ...
Oui mais...le PostgreSQL "Enterprise" dEDB a des hints ! Cest quand même bien la preuve que cest utile ! Hmmmm peut-être...mais cest peut-être aussi la preuve quil faut avoir la même liste de fonctionnalités que les autres, même si la fonctionnalité en question est plus nuisible quutile.
Oui mais...rien ne peut vous convaincre. Il vous FAUT les hints pour ne pas vivre avec la peur dêtre coincé si le planner devient fou. Nous allons donc montrer dans la suite de cet article que PostgreSQL dispose en pratique de cette fonctionnalité. Cela passe par une extension dont linstallation est très simple :
Je reprends lexemple de cet article au cours duquel nous avons vu que le plan utilisant le B-Tree était inefficace lors de la recherche sur 10% des données. Nous allons forcer le plan pour obliger PostgreSQL à balayer complètement la table :
Oui mais ... (bis)
Voilà il suffit de charger la librairie pg_hint_plan puis de préfixer notre requête par le hint /*+ SeqScan(population)*/ pour obtenir le résultat souhaité. Bravo, nous avons gagné 1s1 sur un cas particulier ! Mais il y a un hic. Imaginez que la table accueille les données dautres régions françaises et que la part des LEFEVRE tombe à 1% du total. Nous allons continuer à forcer un balayage complet de la table. Le hint nest en effet PAS un conseil cest un ORDRE.
Oui mais quand même il a été bien utile ce hint non ? Et bien pas tant que ça. Ici je mens à PostgreSQL. Pas sur le contenu de la table car le planner sait que les LEFEVRE représentent 10% des données. Mais il ne sait pas que ma RAM est suffisante pour stocker toutes les données de ma base. Les I/O aléatoires ne sont donc pas plus coûteuses que les I/O séquentielles. Et si je donnais cette précieuse information au planner ?
Que sest-il passé ?!?
Ma requête avec hint est battue à plate couture : nous obtenons le résultat plus de 2 fois plus rapidement ! PostgreSQL considère par défaut que les I/O aléatoires (random_page_cost) sont 4 fois plus coûteuses que les I/O séquentielles (seq_page_cost), il estime en effet que les I/O aléatoires sont 40 fois plus lentes par nature mais que nous allons demander des données en cache dans 90% des cas. Je lui dis en ramenant random_page_cost à 1 quil peut considérer que tout est en cache, il choisit donc de passer par lindex de manière classique (index scan).
Si vous êtes vraiment fanatique des hints vous pouvez bien sûr obtenir le "bon" plan (qui nest bon que parce que le cas est particulier !) en le forçant :
Conclusion
Les hints sont très rarement intéressants mais ils sont parfaitement utilisables avec PostgreSQL. Ne le dites à personne ;) !