adauhr / pg_frapi

Une collection de fonctions pl/pgsql permettant d'appeler des API web de l'administration française. (Version alpha!)
MIT License
3 stars 0 forks source link

Probleme de performance de adresse_search_format() en fonction de la syntaxe. #1

Open MarHoff opened 7 years ago

MarHoff commented 7 years ago

L'un des intérêt majeur de pg_frapi est de pouvoir géocoder des enregistrements directement dans postgresql. Ajouter les colonnes géocodée à une ligne existante est donc un cas d'usage particulièrement classique de ces fonctions.

Cependant dans sa version actuelle la manière dont les fonction sont appelés a un impact dramatique sur la performance. Les ordre de grandeur exprimé en millisecondes ci-dessous s'entendent "à chaud" (c'est à dire après un appelle initial à l'API adresse.data.gouv.fr) en effet j'ai constaté que le premier appel d'une série au géo-codeur peut prendre plusieurs seconde, sans doute à cause d'un mécanisme de stand-by coté serveur qui n'est pas du ressort de pg_frapi.

1. Ajouter une valeur brut de type jsonb à un tableau existant

SELECT 'f1 value'::text f1 , frapi.adresse_search_json('route des anges, landéda')

On obtient des temps de réponse qui tendent vers les 100ms/ligne (limite fair-use de l'API)

2. Ajouter une valeur brut de type _record::frapi.adressesearch à un tableau existant

SELECT 'f1 value'::text f1 , frapi.adresse_search('route des anges, landéda')

On obtient des temps de réponse similaires avec un overhead acceptable.

3. Ajouter les colonnes d'adressage à un tableau existant sans sous-requète

SELECT 'f1 value'::text f1 , (frapi.adresse_search('route des anges, landéda')).*

Avec cette syntaxe, le planner va en réalité exécuter chaque fonction plusieurs fois (une fois pour chaque champs à déplier). Dans la version 0.1 ce problème est aggravé car les fonctions on été définies comme VOLATILE alors que le statut STABLE devrait être suffisant. Au bout du compte on obtient des temps de réponses pouvants allers jusqu'à 1200 ms/ligne! Cette syntaxe est donc à éviter à tout prix! Elle est peu performante et sollicite inutilement l'API

4. Ajouter les colonnes d'adressage à un tableau existant avec sous-requète

SELECT f1, (adresse_search).* FROM (
SELECT 'f1 value'::text f1 , frapi.adresse_search('route des anges, landéda')
) foo

On retrouve des performance similaire au requête 1 & 2 car la sous-requète contraint le planner à n’exécuter la fonction qu'une seule fois.

A améliorer:

Il conviendrait donc de voir s'il n'est pas possible de rendre la syntaxe 3 plus performante par un meilleur paramétrage des fonctions. Il faudrait aussi tester ce comportement sur d'autre version de PostgreSQL car ce problème pourrait également se résoudre via une amélioration du planner.

MarHoff commented 7 years ago

A priori ce comportement est conforme à la documentation de PostgreSQL qui indique que ce type de syntaxe SELECT (myfunc(x)).* FROM some_table; se traduit toujours par ceci au niveau de l'interpreteur SELECT (myfunc(x)).a, (myfunc(x)).b, (myfunc(x)).c FROM some_table;

MarHoff commented 7 years ago

Pour référence le problème de performance à été évoqué ici: http://www.cybertec.at/func-hidden-performance-issues/