91 votes

Obtenir le temps d'exécution d'une requête PostgreSQL

DECLARE @StartTime datetime,@EndTime datetime

SELECT @StartTime=GETDATE()

select distinct born_on.name
from   born_on,died_on
where (FLOOR(('2012-01-30'-born_on.DOB)/365.25) <= (
    select max(FLOOR((died_on.DOD - born_on.DOB)/365.25))
    from   died_on, born_on
    where (died_on.name=born_on.name))
    )
and   (born_on.name <> All(select name from died_on))

SELECT @EndTime=GETDATE()

SELECT DATEDIFF(ms,@StartTime,@EndTime) AS [Duration in millisecs]

Je ne parviens pas à obtenir le temps d'interrogation. Au lieu de cela, j'obtiens l'erreur suivante :

sql:/home/an/Desktop/dbms/query.sql:9: ERROR:  syntax error at or near "@"
LINE 1: DECLARE @StartTime datetime,@EndTime datetime

174voto

Peter Points 446

Si vous voulez dire dans psql, plutôt que dans un programme que vous écrivez, utilisez \? pour l'aide, et voir :

\timing [on|off]       toggle timing of commands (currently off)

Et ensuite vous obtenez des résultats comme :

# \timing on
Timing is on.

# select 1234;        
 ?column? 
----------
     1234
(1 row)

Time: 0.203 ms

124voto

Erwin Brandstetter Points 110228

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.

51voto

filiprem Points 1785

PostgreSQL n'est pas Transact-SQL. Il s'agit de deux choses légèrement différentes.

Dans PostgreSQL, ce serait quelque chose du type

DO $proc$
DECLARE
  StartTime timestamptz;
  EndTime timestamptz;
  Delta double precision;
BEGIN
  StartTime := clock_timestamp();
  PERFORM foo FROM bar; /* Put your query here, replacing SELECT with PERFORM */
  EndTime := clock_timestamp();
  Delta := 1000 * ( extract(epoch from EndTime) - extract(epoch from StartTime) );
  RAISE NOTICE 'Duration in millisecs=%', Delta;
END;
$proc$;

D'autre part, la mesure du temps d'interrogation ne doit pas être aussi compliquée. Il existe de meilleures méthodes :

  1. Sur client de ligne de commande postgres il existe un \timing qui mesure le temps de requête du côté client (similaire à la durée dans le coin inférieur droit de SQL Server Management Studio).

  2. Il est possible de enregistrer la durée de la requête dans le journal du serveur (pour chaque requête, ou seulement lorsqu'elle a duré plus de X millisecondes).

  3. Il est possible de collecter le timing côté serveur pour n'importe quelle déclaration unique en utilisant la fonction EXPLAIN commandement :

    EXPLAIN (ANALYZE, BUFFERS) YOUR QUERY HERE;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X