Comment puis-je comparer une requête PostgreSQL?

34

Je souhaite analyser une requête contenant une fonction définie par l'utilisateur que j'ai écrite pour PostgreSQL. Existe-t-il des méthodes standard pour exécuter un tel point de référence?

Je sais que le timing peut être activé avec \timingl'invite psql, mais idéalement, j'aimerais avoir un script qui s'occupe de tout automatiquement: lancer la requête plusieurs fois, vider le cache PostgreSQL après chaque exécution (probablement en redémarrant le fichier PostgreSQL service), et la sortie du temps moyen d'exécution (et la mémoire utilisée est un plus).

Franck Dernoncourt
la source
3
Consultez pgbench; vous pouvez l'exécuter avec des scripts personnalisés pour faire ce que vous voulez. Avec un script shell pour arrêter et redémarrer Pg et pour supprimer le cache de disque du système d'exploitation, vous disposez de la majeure partie de ce dont vous avez besoin.
Craig Ringer
Pas tout à fait un double de dba.stackexchange.com/questions/3148/… .
Jon of All Trades

Réponses:

29

L'outil le plus utilisé est la commande SQL EXPLAIN ANALYZE, avec éventuellement plus d'options pour plus de détails dans la réponse. Cela génère le plan de requête avec les estimations du planificateur et les temps d'exécution réels.

Pourquoi voudriez-vous vider le cache? Le cas d'utilisation généralement plus probable est que le cache est rempli. Si vous souhaitez toujours suivre cette voie, voici une réponse connexe sur SO .

Ne pas réinitialiser le cache, voici deux méthodes simples pour tester plusieurs itérations:

UDF simple

EXPLAIN ANALYZE
SELECT f_myfunc(g) FROM generate_series (1,1000) AS t(g);

Ou avec entrée aléatoire - nombres aléatoires compris entre 0 et 5000 dans l'exemple:

EXPLAIN ANALYZE
SELECT f_myfunc((random()*5000)::int) FROM generate_series (1,1000) AS t(g);

Ou avec une vraie table de vie:

EXPLAIN ANALYZE
SELECT f_myfunc(my_column) FROM my_tbl;   -- LIMIT n

Fonctions / requêtes plus complexes

CREATE FUNCTION f_test(ct int, sql text) RETURNS void AS
$func$
DECLARE
   i int;
BEGIN

FOR i IN 1 .. $1 LOOP
    EXECUTE sql;  -- not safe against SQLi!
END LOOP;

END
$func$ LANGUAGE plpgsql

Appel:

EXPLAIN ANALYZE
SELECT f_test(100, $x$SELECT * from MADLIB.gp('mock3', '{x1, x2, x3}', '{y1}', 100,20, 3)$x$

Attention : la requête est réellement exécutée!
Attention : Ne convient pas pour un usage public. Injection SQL possible.

Encore une fois, vous pouvez utiliser des paramètres aléatoires si nécessaire. Peut-être avec la USINGclause de EXECUTE.

Erwin Brandstetter
la source