pgbench — Réalise un test de benchmark pour PostgreSQL
pgbench
-i
[option
...] [nom_base
]
pgbench
[option
...] [nom_base
]
pgbench est un programme pour réaliser simplement des
tests de performances (benchmark)
sur PostgreSQL. Il
exécute la même séquence de commandes SQL en continu, potentiellement
avec plusieurs sessions concurrentes puis calcule le taux de
transactions moyen (en transactions par secondes).
Par défaut, pgbench teste un scénario
vaguement basé sur TPC-B, impliquant cinq commandes SELECT
,
UPDATE
et INSERT
par
transaction.
Toutefois, il est facile de tester d'autres scénarios en écrivant
vos propres scripts de transactions.
Une sortie classique de pgbench ressemble à ceci :
transaction type: <builtin: TPC-B (sort of)> scaling factor: 10 query mode: simple number of clients: 10 number of threads: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 tps = 85.184871 (including connections establishing) tps = 85.296346 (excluding connections establishing)
Les six premières lignes rapportent quelques-uns des paramètres
les plus importants qui ont été définis.
La ligne suivante remonte le nombre de transactions réalisées et
prévues. (La seconde rapporte juste le ratio entre le nombre de
clients et le nombre de transactions par client).
Ils seront équivalents à moins que l'exécution ait échoué avant la fin.
(Avec le mode -T
, seul le nombre réel de transactions
est affiché.)
Les deux dernières lignes remontent le nombre de transactions par
secondes incluant ou pas le temps utilisé à démarrer une session.
Les transactions de ce test, proche de TPC-B, nécessitent d'avoir défini
au préalable quelques tables spécifiques.
pgbench devrait être utilisé avec l'option
-i
(initialisation) pour créer et remplir ces tables.
(Si vous testez un script personnalisé, vous n'aurez pas besoin de
cette étape, mais vous aurez besoin de mettre en place tout ce dont
votre script aura besoin).
Une initialisation ressemble à cela :
pgbench -i [autres-options
]nom_base
où nom_base
est le nom de la base de données
pré-existante sur laquelle on conduit les tests. (Vous aurez aussi
probablement besoin des options -h
,
-p
et/ou -U
pour spécifier comment
se connecter au serveur de base de données.)
pgbench -i
crée quatre tables nommées
pgbench_accounts
,
pgbench_branches
,
pgbench_history
et
pgbench_tellers
,
détruisant toute table qui porterait l'un de ces noms.
Attention à utiliser une autre base de données si vous avez
des tables qui portent ces noms !
Par défaut, avec un facteur d'échelle de 1, les tables contiennent initialement les nombres de lignes suivant :
table # de lignes --------------------------------- pgbench_branches 1 pgbench_tellers 10 pgbench_accounts 100000 pgbench_history 0
Vous pouvez (et, dans la plupart des cas, devriez) augmenter le nombre de
lignes en utilisant l'option -s
. Le facteur de remplissage
-F
peut aussi être utilisée à cet effet.
Une fois la mise en place terminée, vous pouvez
lancer vos benchmarks sans inclure l'option -i
,
c'est-à-dire :
pgbench [options
]nom_base
Dans presque tous les cas, vous allez avoir besoin de certaines
options pour rendre vos tests plus pertinents.
Les options les plus importantes sont :
-c
(le nombre de clients),
-t
(le nombre de transactions),
-T
(l'intervalle de temps)
et -f
(le script à lancer).
Vous trouverez ci-dessous toutes les options disponibles.
La partie suivante est divisée en trois sous-parties : des options différentes sont utilisées pendant l'initialisation et pendant les tests ; certaines options sont utiles dans les deux cas.
Pour réaliser l'initialisation, pgbench accepte les arguments suivants en ligne de commande :
-i
--initialize
Nécessaire pour passer en mode initialisation.
-F
fillfactor
--fillfactor=
fillfactor
Crée les tables pgbench_accounts
,
pgbench_tellers
et
pgbench_branches
avec le facteur de
remplissage (fillfactor) spécifié.
La valeur par défaut est 100.
-n
--no-vacuum
Ne réalise pas de VACUUM après l'initialisation.
-q
--quiet
Passe du mode verbeux au mode silencieux, en n'affichant qu'un message toutes les 5 secondes. Par défaut, on affiche un message toutes les 100 000 lignes, ce qui engendre souvent plusieurs lignes toutes les secondes (particulierement sur du bon matériel)
-s
scale_factor
--scale=
scale_factor
Multiplie le nombre de lignes générées par le facteur d'échelle
(scale factor). Par exemple,
-s 100
va créer 10 millions de
lignes dans la table pgbench_accounts
. La
valeur par défaut est 1. Lorsque l'échelle dépasse 20 000, les
colonnes utilisées pour contenir les identifiants de compte (colonnes
aid
) vont être converties en grands entiers
(bigint
), de manière à être suffisamment grandes pour
contenir l'espace des identifiants de compte.
--foreign-keys
Crée des contraintes de type clé étrangère entre les tables standards.
--index-tablespace=index_tablespace
Crée un index dans le tablespace spécifié plutôt que dans le tablespace par défaut.
--tablespace=tablespace
Crée une table dans le tablespace spécifié plutôt que dans le tablespace par défaut.
--unlogged-tables
Crée toutes les tables en tant que tables non journalisées (unlogged tables) plutôt qu'en tant que tables permanentes.
Pour réaliser un benchmark pgbench accepte les arguments suivants en ligne de commande :
-b
nom_script[@poids]
--builtin
=nom_script[@poids]
Ajoute le script interne spécifié à la liste des scripts à exécuter.
Les scripts internes disponibles sont tpcb-like
,
simple-update
et select-only
.
L'utilisation des préfixes non ambigus des noms de scripts internes
est acceptée. En utilisant le nom spécial list
, la
commande affiche la liste des scripts internes, puis quitte
immédiatement.
En option, il est possibl d'écrire un poids en entier après
@
pour ajuster la probabilité de sélectionner ce
script plutôt que les autres. Le poids par défaut est de 1. Voir
ci-dessous pour les détails.
-c
clients
--client=
clients
Nombre de clients simulés, c'est-à-dire le nombre de sessions concurentes sur la base de données. La valeur par défaut est à 1.
-C
--connect
Établit une nouvelle connexion pour chaque transaction, plutôt que de ne le faire qu'une seule fois par session cliente. C'est une option très utile pour mesurer la surcharge engendrée par la connexion.
-d
--debug
Affiche les informations de debug.
-D
variable
=
value
--define=
variable
=
value
Définit une variable à utiliser pour un script personnalisé
Voir ci-dessous pour plus de détails.
Il est possible d'utiliser plusieurs fois l'option -D
.
-f
nom_fichier[@poids]
--file=
nom_fichier[@poids]
Ajoute un script de transactions nommé
nom_fichier
à la liste des scripts à
exécuter.
En option, il est possible d'écrire un poids sous la forme d'un entier
après le symbole @
pour ajuster la probabilité de
sélectionner ce script plutôt qu'unautre. Le poids par défaut est de
1. (Pour utiliser un nom de fichier incluant un caractère
@
, ajoutez un poids pour qu'il n'y ait pas
d'ambiguité, par exemple filen@me@1
.) Voir
ci-dessous pour les détails.
-j
threads
--jobs=
threads
Nombre de processus utilisés dans pgbench. Utiliser plus d'un thread peut être utile sur des machines possédant plusieurs cœurs. Les clients sont distribués de la manière la plus égale possible parmi les threads. La valeur par défaut est 1.
-l
--log
Rapporte les informations sur chaque transaction dans un fichier journal. Voir ci-dessous pour plus de détails.
-L
limite
--latency-limit=
limite
Les transactions durant plus de limite
millisecondes
sont comptabilisée et rapportées séparement en tant que
late.
Lorsqu'un bridage est spécifié(--rate=...
),
les transactions qui accusent un retard sur la planification supérieur à
limite
millisecondes, et celles
qui n'ont aucune chance de respecter la limite de latence
ne sont pas du tout envoyées au serveur.
Elles sont comptabilisées et rapportées séparément en tant que
skipped (ignorées).
-M
querymode
--protocol=
querymode
Protocole à utiliser pour soumettre des requêtes au serveur :
simple
: utilisation du protocole
de requêtes standards.
extended
: utilisation du protocole
de requête étendu.
prepared
: utilisation du protocole
de requête étendu avec instructions préparées.
Par défaut, le protocole de requête standard est utilisé (voir Chapitre 52 pour plus d'informations).
-n
--no-vacuum
Ne réalise pas de VACUUM avant de lancer le test.
Cette option est nécessaire si vous lancez
un scénario de test personnalisé qui n'utilise pas les tables
standards pgbench_accounts
,
pgbench_branches
,
pgbench_history
et pgbench_tellers
.
-N
--skip-some-updates
Exécute le script interne simple-update. Raccourci pour
-b simple-update
.
-P
sec
--progress=
sec
Affiche un rapport de progression toutes les
sec
secondes.
Ce rapport inclut la durée du test, le nombre de
transactions par seconde depuis le dernier rapport et la
latence moyenne des transactions, ainsi que la déviation
depuis le dernier rapport.
Avec le bridage (option -R
), la latence est calculée
en fonction de la date de démarrage ordonnancée de la transaction et non
de son temps de démarrage réel, donc elle inclut aussi la latence
moyenne du temps d'ordonnancement.
-r
--report-latencies
Rapporte la latence moyenne par instruction (temps d'exécution du point de vue du client) de chaque commande après la fin du benchmark. Voir ci-dessous pour plus de détails.
-R
rate
--rate=
rate
Exécute les transactions en visant le débit spécifié, au lieu d'aller le plus vite possible (le défaut). Le débit est donné en transactions par seconde. Si le débit visé est supérieur au maximum possible, la limite de débit n'aura aucune influence sur le résultat.
Pour atteindre ce débit, les transactions sont ordonnancées avec une distribution suivant une loi de Poisson. La date de démarrage prévue se calcule depuis le moment où le client a démarré et pas depuis le moment où la dernière transaction s'est achevée. Cette approche signifie que, si une transaction dépasse sa date de fin prévue, un rattrapage est encore possible pour les suivantes.
Lorsque le bridage est actif, la latence de la transaction rapportée en fin de test est calculée à partir des dates de démarrage ordonnancées, c'est-à-dire qu'elle inclue le temps où chaque transaction attend que la précédente se termine. Le temps d'attente est appelé temps de latence d'ordonnancement, et ses valeurs moyenne et maximum sont rapportées séparément. La latence de transaction par rapport au temps de démarrage réel, c'est-à-dire le temps d'exécution de la transaction dans la base, peut être récupéré en soustrayant le temps de latence d'ordonnancement à la latence précisée dans les journaux.
Si l'option --latency-limit
est utilisée avec
l'option --rate
, une transaction peut avoir
une telle latence qu'elle serait déja supérieure à limite de
latence lorsque la transaction précédente se termine, car la
latence est calculée au moment de la date de démarrage planifiée.
Les transactions concernées ne sont pas envoyées à l'instance,
elles sont complètement ignorées et comptabilisées séparément.
Une latence de planification élevée est une indication que le système n'arrive pas à traiter les transactions à la vitesse demandée, avec les nombres de clients et threads indiqués. Lorsque le temps moyen d'exécution est plus important que l'intervalle prévu entre chaque transaction, les transactions vont prendre du retard une-à-une, et la latence de planification va continuer de croître tout le long de la durée du test. Si cela se produit, vous devrez réduire le taux de transaction que vous avez spécifié.
-s
scale_factor
--scale=
scale_factor
Affiche le facteur d'échelle dans la sortie de pgbench.
Avec les tests internes, ce n'est pas nécessaire ; le facteur
d'échelle approprié sera détecté en comptant le nombre de lignes
dans la table pgbench_branches
.
Toutefois, lors de l'utilisation d'un benchmark avec un scénario
personnalisé (option -f
), le facteur
d'échelle sera affiché à 1 à moins que cette option soit utilisée.
-S
--select-only
Exécute le script interne select-only. Raccourci pour
-b select-only
.
-t
transactions
--transactions=
transactions
Nombre de transactions lancées par chaque client. La valeur par défaut est 10.
-T
seconds
--time=
seconds
Lance le test pour la durée spécifiée en secondes, plutôt que
pour un nombre fixe de transactions par client.
Les options -t
et -T
ne sont
pas compatibles.
-v
--vacuum-all
Réalise un VACUUM sur les quatre tables standards avant de
lancer le test. Sans l'option -n
ou
-v
, pgbench lancera un VACUUM
sur les tables pgbench_tellers
et
pgbench_branches
, puis tronquera
pgbench_history
.
--aggregate-interval=
secondes
Taille de l'intervalle d'agrégation (en secondes). Ne peut être utilisée qu'avec l'option -l. Avec cette option, le journal contiendra des résumés par intervalle, comme décrit ci-dessous.
--log-prefix=prefix
Définit le préfixe des fichiers logs créés par --log
.
Le défaut est pgbench_log
.
--progress-timestamp
Lorsque la progression est affichée (option -P
),
utilise un horodatage de type timestamp (epoch Unix) au lieu d'un
nombre de secondes depuis le début de l'exécution. L'unité est la
seconde avec une précision en millisecondes après le point. Ceci
aide à comparer les traces générées par différents outils.
--sampling-rate=
rate
Taux d'échantillonnage utilisé lors de l'écriture des données dans les journaux, afin d'en réduire la quantité. Si cette option est utilisée, n'y sera écrite que la proportion indiquée des transactions. 1.0 signifie que toutes les transactions seront journalisées, 0.05 signifie que 5% de toutes les transactions le seront.
Pensez à prendre le taux d'échantillonnage en compte en consultant le journal. Par exemple, lorsque vous évaluez le nombre de transactions par seconde, vous devrez multiplier les nombres en conséquence. (Par exemple, avec un taux d'échantillonage de 0.01, vous n'obtiendrez que 1/100 du tps réel).
pgbench accepte les arguments suivants en ligne de commande :
-h
hostname
--host=
hostname
Le nom du serveur de base de données
-p
port
--port=
port
Le port d'écoute de l'instance sur le serveur de base de données
-U
login
--username=
login
Le nom de l'utilisateur avec lequel on se connecte
-V
--version
Affiche la version de pgbench puis quitte.
-?
--help
Affiche l'aide sur les arguments en ligne de commande de pgbench puis quitte.
pgbench exécute des scripts de tests choisis de
façon aléatoire à partir d'une sélection. Les scripts pourraient inclure
des scripts internes indiqués avec l'option -b
et des
scripts fournis par l'utilisateur indiqués avec l'option
-f
. Chaque script peut se voir affecter un poids
spécifique après un caractère @
pour modifier sa
probabilité de sélection. Le poids par défaut est de 1
.
Les scripts avec un poids de 0
sont ignorés.
Le script interne par défaut (aussi appelé avec -b tpcb-like
)
exécute sept commandes par transaction choisies de
façon aléatoire parmi aid
, tid
,
bid
et delta
. Le scénario s'inspire
du jeu de tests de performance TPC-B benchmark mais il ne s'agit pas
réellement de TPC-B, d'où son nom.
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta
WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts
WHERE aid = :aid;
UPDATE pgbench_tellers
SET tbalance = tbalance + :delta
WHERE tid = :tid;
UPDATE pgbench_branches
SET bbalance = bbalance + :delta
WHERE bid = :bid;
INSERT
INTO pgbench_history (tid, bid, aid, delta, mtime)
VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;
Si vous sélectionnez le script interne simple-update
(ou
-N
), les étapes 4 et 5 ne sont pas inclus dans la
transaction. Ceci évitera des contentions au niveau des mises à jour sur
ces tables mais le test ressemblera encore moins à TPC-B.
Si vous sélectionnez le script interne select-only
(ou
-S
), alors seul le SELECT
est exécuté.
pgbench est capable d'utiliser des
scénarios de test de performances personnalisés, en remplaçant le
script de transactions par défaut (décrit ci-dessus) par un script de
transactions lu depuis un fichier spécifié avec l'option
(-f
).
Dans ce cas, une « transaction » est comptabilisée comme
une exécution du fichier script.
Un fichier script contient une ou plusieurs commandes SQL terminées par des
points-virgules. Les lignes vides et les lignes commençant par
--
sont ignorées. Les fichiers scripts peuvent aussi
contenir des « méta-commandes », qui seront interprétées par
pgbench comme indiqué plus bas.
Avant PostgreSQL 9.6, les commandes SQL compris dans les fichiers scripts étaient terminées par un retour à la ligne. Elles ne pouvaient donc pas être écrites sur plusieurs lignes. Maintenant, un point-virgule est requis pour séparer des commandes SQL consécutives (bien qu'une commande SQL n'en a pas besoin si elle est suivie par une méta-commande). Si vous avez besoin de créer un fichier script qui fonctionne avec les anciennes et nouvelles versions de pgbench, assurez-vous d'écrire chaque commande SQL sur une seule ligne et en terminant avec un point-virgule.
Il est possible de procéder facilement à de la substitution de variables
dans les fichiers scripts.
Les variables peuvent être instanciées via
l'option -D
de la ligne de commande comme décrit ci-dessus,
ou grâce aux méta-commandes décrites ci-dessous.
En plus des commandes pré-définies par l'option de la ligne de
commande -D
, quelques variables sont
automatiquement prédéfinies, listées sous
Tableau 242.
Une valeur de ces variables définie via l'option -D
aura priorité sur la valeur définie
automatiquement. Une fois définie, la valeur d'une variable peut
être insérée dans les commandes SQL en écrivant :
nom_variable
.
S'il y a plus d'une session par client, chaque session possède son
propre jeu de variables.
Tableau 242. Variables automatiques
Variable | Description |
---|---|
scale | facteur d'echelle courant |
client_id | nombre unique permettant d'identifier la session client (commence à zero) |
Dans les fichiers de scripts, les méta-commandes commencent avec un anti-
slash (\
) et s'étendent jusqu'à la fin de la ligne,
même si elles peuvent s'étendre sur plusieurs lignes en écrivant anti-slash
puis un retour chariot. Les
arguments d'une méta-commande sont séparés par des espaces vides. Les
méta-commandes suivantes sont supportées :
\set nom_variable
expression
Définit la variable nom_variable
à une valeur
définie par expression
. L'expression peut
contenir des constantes entières comme 5432
,
ou à double précision comme 3.14159
, des références à
des variables :
nom_variable
,
des opérateurs unitaires (+
, -
) et
binaires (+
, -
,
*
, /
, %
) avec
leur précédence et associativité habituelles, des
appels de fonction, et
des parenthèses.
Exemples :
\set ntellers 10 * :scale \set aid (1021 * random(1, 100000 * :scale)) % \ (100000 * :scale) + 1
\sleep
nombre
[ us | ms | s ]
Entraîne la suspension de l'exécution du script pendant la durée
spécifiée en microsecondes (us
), millisecondes
(ms
) ou secondes (s
).
Si l'unité n'est pas définie, l'unité par défaut est la seconde.
Ce peut être soit un entier constant, soit une référence
:
nom_variable
vers
une variable retournant un entier.
Exemple :
\sleep 10 ms
\setshell nom_variable
commande
[
argument
... ]
Définit la variable nom_variable
comme le
résultat d'une commande shell nommée commande
aves le(s) argument
(s) donné(s). La commande
doit retourner un entier sur la sortie standard.
commande
et chaque
argument
peuvent être soit une constante de
type text, soit une référence
:
nom_variable
à une variable.
Si vous voulez utiliser un argument
commençant
avec un symbole deux-points, écrivez un deux-points supplémentaire au
début de argument
.
Exemple :
\setshell variable_à_utiliser commande argument_litéral :variable ::literal_commencant_avec_deux_points
\shell commande
[ argument
... ]
Identique à \setshell
, mais le résultat de la
commande sera ignoré.
Exemple :
\shell command literal_argument :variable ::literal_starting_with_colon
Les fonctions listées dans Tableau 243 sont
internes à pgbench et peuvent être
utilisées dans des expressions apparaissant dans
\set
.
Tableau 243. Fonctions pgbench
Fonction | Type de retour | Description | Exemple | Résultat |
---|---|---|---|---|
| identique à a | valeur absolue | abs(-17) | 17 |
| identique à a | affiche a sur stderr,
et renvoie a | debug(5432.1) | 5432.1 |
| double | convertit vers le type double | double(5432) | 5432.0 |
| double si a est double, sinon integer | valeur la plus grande parmi les arguments | greatest(5, 4, 3, 2) | 5 |
| integer | convertie en int | int(5.4 + 3.8) | 9 |
| double si a est double, sinon integer | plus petite valeur parmi les arguments | least(5, 4, 3, 2.1) | 2.1 |
| double | valeur de la constante PI | pi() | 3.14159265358979323846 |
| integer | entier aléatoire uniformément distribué dans [lb, ub] | random(1, 10) | un entier entre 1 et 10 |
| integer | entier aléatoire distribué exponentiellement dans [lb, ub] ,
voir ci-dessous | random_exponential(1, 10, 3.0) | un entier entre 1 et 10 |
| integer | entier aléatoire distribué de façon gaussienne dans [lb, ub] ,
voir ci-dessus | random_gaussian(1, 10, 2.5) | un entier entre 1 et 10 |
| double | racine carrée | sqrt(2.0) | 1.414213562 |
La fonction random
génère des valeurs en utilisant une
distribution uniforme ; autrement dit toutes les valeurs sont dans
l'intervalle spécifiée avec une probabilité identique. Les fonctions
random_exponential
et
random_gaussian
requièrent un paramètre supplémentaire
de type double qui détermine le contour précis de cette distribution.
Pour une distribution exponentielle,
parameter
contrôle la distribution en
tronquant une distribution exponentielle en décroissance rapide à
parameter
, puis en projetant le résultant sur
des entiers entre les limites. Pour être précis :
f(x) = exp(-parameter * (x - min) / (max - min + 1)) / (1 - exp(-parameter))
Puis la valeur i
entre les valeurs
min
et max
, en les
incluant, est récupérée avec la probabilité :
f(i) - f(i + 1)
.
Intuitivement, plus parameter
est grand, plus
les valeurs fréquentes proches de min
sont
accédées et moins les valeurs fréquentes proches de
max
sont accédées. Plus
parameter
est proche de 0, plus la
distribution d'accès sera plate (uniforme). Une approximation grossière de
la distribution est que 1% des valeurs les plus fréquentes de
l'intervalle, proches de min
, sont tirées
parameter
% du temps. La valeur de
parameter
doit être strictement positive.
Pour une distribution gaussienne, l'intervalle correspond à une
distribution normale standard (la courbe gaussienne classique en forme
de cloche) tronquée à -parameter
à gauche et à
+parameter
à droite.
Les valeurs au milieu de l'intervalle sont plus
susceptibles d'être sélectionnées. Pour être précis, si
PHI(x)
est la fonction de distribution cumulative de
la distribution normale standard, avec une moyenne mu
définie comme (max + min) / 2.0
, avec
f(x) = PHI(2.0 * parameter * (x - mu) / (max - min + 1)) /
(2.0 * PHI(parameter) - 1)
alors la valeur value i
entre
min
et max
(inclus) est sélectionnée avec une probabilité :
f(i + 0.5) - f(i - 0.5)
. Intuitivement, plus
parameter
est grand, et plus les valeurs
fréquentes proches du centre de l'intervalle sont sélectionnées, et
moins les valeurs fréquentes proches des bornes
min
et max
.
Environ 67% des valeurs sont sélectionnées à partir du centre
1.0 / parameter
, soit
0.5 / parameter
autour de la moyenne, et 95% dans le
centre 2.0 / parameter
, soit
1.0 / parameter
autour de la moyenne ; par
exemple, si parameter
vaut 4.0, 67% des
valeurs sont sélectionnées depuis le quart du milieu (1.0 / 4.0) de
l'intervalle (ou à partir de 3.0 / 8.0
jusqu'à
5.0 / 8.0
) et 95% depuis la moitié du milieu
(2.0 / 4.0
) de l'intervalle (deuxième et troisième
quartiles). Le parameter
minimum est 2.0 pour
les performances de la transformation Box-Muller.
En tant qu'exemple, la définition complète de la construction de la transaction style TPC-B est :
\set aid random(1, 100000 * :scale) \set bid random(1, 1 * :scale) \set tid random(1, 10 * :scale) \set delta random(-5000, 5000) BEGIN; UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; SELECT abalance FROM pgbench_accounts WHERE aid = :aid; UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); END;
Ce script autorise chaque itération de la transaction à référencer des lignes différentes, sélectionnées aléatoirement. (Cet exemple montre aussi pourquoi il est important que chaque session cliente ait ses propres variables -- sinon elles n'affecteront pas les différentes lignes de façon indépendantes.
Avec l'option -l
(mais sans l'option
--aggregate-interval
),
pgbench va écrire des informations sur
chaque transaction dans un fichier journal. Il sera nommé
,
où prefix
.nnn
prefix
vaut par défaut
pgbench_log
, et nnn
est le PID
du processus pgbench.
Le préfixe peut être changé avec l'option --log-prefix
.
Si l'option -j
est positionnée à 2 ou plus,
créant plusieurs processus de travail (worker),
chacun aura son propre fichier journal.
Le premier worker utilisera le même nom pour son fichier journal
que dans le cas d'un seul processus.
Les fichiers journaux supplémentaires s'appelleront
,
où prefix
.nnn
.mmm
mmm
est un numéro de séquence,
identifiant chaque worker, commençant à 1.
Le format du journal est le suivant :
id_client
no_transaction
temps
no_script
time_epoch
time_us
[schedule_lag
]
où
client_id
indique la session client qui a exécuté
la transaction, transaction_no
compte le nombre
de transactions exécutées par cette session,
temps
est la durée totale de la
transaction en microsecondes, no_script
indique quel fichier script a été utilisé (très utile lorsqu'on
utilise plusieurs scripts avec l'option -f
ou
-b
), et
time_epoch
/time_us
est un horodatage Unix avec un décalage en microsecondes (utilisable pour
créer un horodatage ISO 8601 avec des secondes fractionnées) indiquant
à quel moment la transaction s'est terminée.
Le champ schedule_lag
est la différence
entre la date de début planifiée de la transaction et sa date de
début réelle, en micro secondes.
Il est présent uniquement lorsque l'option --rate
est
utilisée.
Quand les options --rate
et --latency-limit
sont utilisées en même temps, le champ time
pour
une transaction ignorée sera rapportée en tant que skipped
.
Ci-dessous un extrait du fichier journal généré avec un seul client :
0 199 2241 0 1175850568 995598 0 200 2465 0 1175850568 998079 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663
Autre exemple avec les options --rate=100
et
--latency-limit=5
(notez
la colonne supplémentaire schedule_lag
) :
0 81 4621 0 1412881037 912698 3005 0 82 6173 0 1412881037 914578 4304 0 83 skipped 0 1412881037 914578 5217 0 83 skipped 0 1412881037 914578 5099 0 83 4722 0 1412881037 916203 3108 0 84 4142 0 1412881037 918023 2333 0 85 2465 0 1412881037 919759 740
Dans cet exemple, la transaction 82 a été en retard, elle affiche une latence (6,173 ms) supérieure à la limite de 5 ms. Les deux transactions suivantes ont été ignorées car elles avaient déjà en retard avant même d'avoir commencé.
Dans le cas d'un test long sur du matériel qui peut
supporter un grand nombre de transactions, les journaux
peut devenir très volumineux.
L'option --sampling-rate
peut être utilisée pour
journaliser seulement un extrait aléatoire des transactions
effectuées.
Avec l'option --aggregate-interval
, les fichiers
journaux utilisent un format quelque peu différent :
début_intervalle
nombre_de_transations
somme_latence
somme_latence_2
latence_minimum
latence_maximum
[somme_retard
somme_retard_2
retard_min
retard_max
[transactions_ignorées
] ]
où début_intervalle
est le début de
l'intervalle (au format epoch Unix),
nombre_de_transations
est le nombre de
transactions dans l'intervalle,
somme_latence
est le cumul des latences dans
l'intervalle,
somme_latence_2
est la somme des carrés des
latences dans l'intervalle,
latence_minimum
est la latence minimum dans
l'intervalle,
et latence_maximum
est la latence maximum dans
l'intervalle.
Les derniers champs somme_retard
,
somme_retard_2
,
retard_min
,
et retard_max
sont présents uniquement si
l'option --rate
a été spécifiée.
Ils fournissent des statistiques sur le temps que chaque transaction a eu à
attendre la fin de la précédente, c'est-à-dire la différence entre la
date de départ prévue et la date de départ réelle de chaque transaction.
Le tout dernier champ,
transactions_ignorées
, n'est présent
que si l'option --latency-limit
est utilisée.
Chaque transaction est comptabilisée dans l'intervalle où elle a committé.
Voici un exemple de sortie :
1345828501 5601 1542744 483552416 61 2573 1345828503 7884 1979812 565806736 60 1479 1345828505 7208 1979422 567277552 59 1391 1345828507 7685 1980268 569784714 60 1398 1345828509 7073 1979779 573489941 236 1411
Notez que tandis que le fichier journal brut (c'est-à-dire non agrégé) contient une référence à quel script a été utilisé pour chaque transaction, le journal agrégé n'en contient pas. De ce fait, si vous avez besoin des données par script, vous devrez agréger ces données vous-même.
Avec l'option -r
, pgbench
collecte le temps de transaction écoulé pour chaque requête
exécutée par chaque client.
Une fois le test de performance terminé, il affiche une
moyenne de ces valeurs, désignée comme latence de chaque requête.
Pour le script par défaut, le résultat aura la forme suivante :
starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 scaling factor: 1 query mode: simple number of clients: 10 number of threads: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 latency average = 15.844 ms latency stddev = 2.715 ms tps = 618.764555 (including connections establishing) tps = 622.977698 (excluding connections establishing) script statistics: - statement latencies in milliseconds: 0.002 \set aid random(1, 100000 * :scale) 0.005 \set bid random(1, 1 * :scale) 0.002 \set tid random(1, 10 * :scale) 0.001 \set delta random(-5000, 5000) 0.326 BEGIN; 0.603 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.454 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 5.528 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 7.335 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.371 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.212 END;
Les moyennes sont rapportées séparément si plusieurs scripts sont spécifiés.
Notez que collecter des informations de chronométrage supplémentaires nécessaires pour calculer la latence par requête rajoute une certaine charge. Cela va réduire la vitesse moyenne calculée pour l'exécution des transactions et réduire le taux calculé des TPS. Le ralentissement varie de manière significative selon la plateforme et le matériel. Comparer la moyenne des valeurs de TPS avec et sans intégration de la latence est une bonne manière de se rendre compte si la surcharge induite par le chronométrage est importante ou pas.
Il est facile d'utiliser pgbench pour produire des résultats complètement dénués de sens ! Voici quelques conseils pour vous aider à obtenir des résultats pertinents.
Tout d'abord, ne croyez jamais en un test qui ne
dure que quelques secondes.
Utilisez l'option -t
ou -T
pour que le test dure au moins quelques minutes, de
façon à lisser le bruit.
Dans certains cas, il vous faudra des heures pour récupérer des
valeurs reproductibles.
C'est une bonne idée de lancer plusieurs fois le test pour voir si vos
chiffres sont ou pas reproductibles.
Pour le scénario de test par défaut typé TPC-B, le facteur d'échelle
d'initialisation (-s
) devrait être au moins
aussi grand que le nombre maximum de clients que vous avez
l'intention de tester (-c
) ; sinon vous allez
principalement tester la contention induite par les mises à jour.
il n'y a que -s
lignes dans la table
pgbench_branches
, et chaque transaction
veut mettre à jour l'une de ces lignes, donc si la valeur de
-c
est supérieure à la valeur de -s
,
il en résultera sûrement de nombreuses transactions bloquées
en attente de la fin d'autres transactions.
Le scénario par défaut est aussi assez sensible au temps écoulé depuis l'initialisation des tables : l'accumulation des lignes et espaces morts dans les tables change les résultats. Pour comprendre ces résultats, vous devez garder une trace du nombre total de mises à jour et du moment du vacuum. Si l'autovacuum est actif, il peut en résulter des variations imprévisibles dans les performances mesurées.
Une limitation de pgbench est qu'il peut lui-même devenir le goulet d'étranglement lorsqu'on essaie de tester avec un grand nombre de sessions clientes. Cela peut être attenué en utilisant pgbench depuis une machine différente du serveur de base de données, bien qu'une faible latence sur le réseau soit dans ce cas essentielle. Il peut même être utile de lancer plusieurs instances parallèles de pgbench, depuis plusieurs machines clientes vers le même serveur de base de données.
Si des utilisateurs non dignes de confiance ont accès à une base de données qui a adopté une méthode sécurisée d'utilisation des schémas, il ne faut pas exécuter pgbench dans cette base. pgbench utilise des noms non qualifiés et ne modifie le chemin de recherche.