Il existe plusieurs façons de mesurer le temps d'exécution, chacune ayant ses avantages et ses inconvénients. Mais quoi que vous fassiez, le "problème de la mesure" s'applique dans une certaine mesure. C'est-à-dire que la mesure elle-même peut fausser le résultat.
1. EXPLAIN ANALYZE
Vous pouvez ajouter au début EXPLAIN ANALYZE
qui présente le plan de requête complet avec les coûts estimés et les temps réellement mesurés. La requête est effectivement exécuté (avec tous les effets secondaires, s'il y en a !). Fonctionne pour SELECT
, INSERT
, UPDATE
, DELETE
.
Vérifiez si ma version adaptée de votre requête est, en fait, plus rapide :
EXPLAIN ANALYZE
SELECT DISTINCT born_on.name
FROM born_on b
WHERE date '2012-01-30' - b.dob <= (
SELECT max(d1.dod - b1.dob)
FROM born_on b1
JOIN died_on d1 USING (name) -- name must be unique!
)
AND NOT EXISTS (
SELECT FROM died_on d2
WHERE d2.name = b.name
);
Exécutez plusieurs fois pour obtenir des temps plus comparables avec le cache chaud. Plusieurs options sont disponibles pour ajuster le niveau de détail.
Bien que principalement intéressé par temps d'exécution total fais-le :
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
En général, TIMING
questions - le manuel :
TIMING
Inclure le temps de démarrage réel et le temps passé dans chaque nœud dans la sortie. La surcharge liée à la lecture répétée de l'horloge du système peut ralentir l'exécution de la fonction ralentir la requête de manière significative sur certains systèmes. paramètre à FALSE
lorsque seul le nombre réel de lignes, et non les heures exactes, sont nécessaires. Le temps d'exécution de l'ensemble de l'instruction est toujours mesuré, même même lorsque la synchronisation au niveau du noeud est désactivée avec cette option. [...]
EXPLAIN ANALYZE
mesures sur le serveur en utilisant l'heure du serveur à partir du système d'exploitation du serveur, en excluant la latence du réseau . Mais EXPLAIN
ajoute une certaine surcharge pour produire également le plan de requête.
2. psql avec \timing
Ou utilisez \timing
dans psql. Comme Peter le démontre.
Le manuel :
\timing [ on | off ]
Avec un paramètre, active ou désactive l'affichage de la durée de chaque instruction SQL. est activé ou désactivé. Sans paramètre, fait basculer l'affichage entre on et désactivé. L'affichage est en millisecondes ; les intervalles supérieurs à 1 seconde sont également affichés au format minutes:secondes, les champs heures et jours étant ajoutés si nécessaire. sont ajoutés si nécessaire.
Différence importante : Mesures psql sur le client en utilisant l'heure locale de l'OS local, donc l'heure comprend la latence du réseau . Il peut s'agir d'une différence négligeable ou énorme en fonction de la connexion et du volume des données renvoyées.
3. Activez log_duration
C'est probablement la méthode qui présente le moins de frais généraux par mesure et qui produit les timings les moins déformés. Mais c'est un peu lourd, car il faut être super-utilisateur, ajuster la configuration du serveur, ne pas pouvoir cibler l'exécution d'une seule requête, et lire les logs du serveur (à moins que vous ne redirigiez sur stdout
).
Le manuel :
log_duration
( boolean
)
Permet d'enregistrer la durée de chaque déclaration terminée. La valeur par défaut de défaut est off
. Seuls les superutilisateurs peuvent modifier ce paramètre.
Pour les clients utilisant le protocole de requête étendu, les durées des étapes Parse, Bind, et Execute sont enregistrées indépendamment.
Il existe des paramètres connexes tels que log_min_duration_statement
.
4. Mesure manuelle précise avec clock_timestamp()
Le manuel :
clock_timestamp()
renvoie l'heure actuelle, et sa valeur change donc même au sein d'une seule commande SQL.
Pour obtenir des temps d'exécution aussi exacts que possible pour les requêtes ad hoc, le mieux que je puisse imaginer est de se baser sur les éléments suivants ce que filiprem a fourni - ce qui est très bien comme ça.
Je l'ai affiné un peu plus pour filtrer l'overhead de mesure - qui peut être important pour les requêtes bon marché (mais généralement pas pour les requêtes coûteuses) - surtout si le système d'exploitation sous-jacent rend les appels de synchronisation coûteux :
DO
$do$
DECLARE
_start_ts1 timestamptz;
_start_ts2 timestamptz;
_start_ts timestamptz;
_end_ts1 timestamptz;
_end_ts2 timestamptz;
_end_ts timestamptz;
_overhead numeric; -- in ms
_timing numeric; -- in ms
BEGIN
_start_ts1 := clock_timestamp();
_end_ts1 := clock_timestamp();
_start_ts2 := clock_timestamp();
_end_ts2 := clock_timestamp();
-- take the minimum as conservative estimate
_overhead := 1000 * extract(epoch FROM LEAST(_end_ts1 - _start_ts1
, _end_ts2 - _start_ts2));
_start_ts := clock_timestamp();
PERFORM 1; -- your query here, replacing the outer SELECT with PERFORM
_end_ts := clock_timestamp();
_timing := 1000 * (extract(epoch FROM _end_ts - _start_ts));
-- RAISE NOTICE 'Timing in ms = %' , _timing; -- optional info
-- RAISE NOTICE 'Timing overhead in ms = %', _overhead;
RAISE NOTICE 'Execution time in ms = %' , _timing - _overhead;
END
$do$
Le coût de la synchronisation elle-même varie énormément, en fonction du système d'exploitation sous-jacent. Pour s'en rendre compte, prenez les heures de début et de fin plusieurs fois et prenez l'intervalle minimum comme estimation prudente de la charge de synchronisation. En outre, l'exécution de la fonction plusieurs fois devrait la réchauffer (si nécessaire).
Après avoir mesuré le temps d'exécution de la requête de charge utile, soustrayez cette surcharge estimée pour vous rapprocher le plus possible du temps réel.
Bien sûr, il est plus judicieux pour les requêtes bon marché de boucler 100 000 fois ou de l'exécuter sur une table de 100 000 lignes si vous le pouvez, afin de rendre insignifiants les bruits parasites.