pgbench — lance un test de performance de PostgreSQL™
pgbench -i [option...] [dbname]
pgbench [option...] [dbname]
pgbench est un programme simple qui exécute un test de performances (benchmark en anglais) sur PostgreSQL™. Il exécute la même séquence de commandes SQL de nombreuses fois, si possible dans plusieurs sessions en parallèle, puis calcule le taux de transaction moyen (transactions par seconde). Par défaut, pgbench teste un scénario vaguement basé sur TPC-B, impliquant cinq SELECT, UPDATE et INSERT par transaction. Néanmoins il est facile de tester d'autres cas en écrivant ses propres fichiers de transaction.
Voici un exemple d'affichage de pgbench :
transaction type: 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 indiquent simplement certains des paramètres les plus importants. La ligne suivant rapporte le nombre de transactions terminées et souhaitées (le dernier étant juste le produit du nombre de clients avec le nombre de transactions par client) ; ils doivent être égaux sauf si un échec est arrivé avant la fin (avec l'option -T, seul le nombre réel de transactions est affiché.) Les deux dernières lignes précisent le taux de transactions, avec et sans le temps de lancement de la session.
Le test de transaction par défaut, ressemblant à TPC-B, nécessite des tables particulières qu'il faut créer. pgbench doit être appelé avec l'option -i (initialisation) pour les créer et les peupler. (Cette étape n'est pas nécessaire dans le cas de script personnalisé, mais la base doit être configurée en conséquence.) L'initialisation ressemble à :
pgbench -i [ autres-options ] nom_base
où nom_base est le nom d'une base de données déjà créée et à utiliser pour les tests. (Les options -h, -p, et/ou -U peuvent être utilisées pour indiquer la façon de se connecter au serveur de bases de données.)
pgbench -i crée quatre tables : pgbench_accounts, pgbench_branches, pgbench_history et pgbench_tellers, détruisant toute table existante de ce nom. Il convient d'y être attentif s'il existe des tables de même nom !
Avec un « facteur d'échelle » de 1, les tables contiennent initialement ce nombre de lignes :
table # de lignes ----------------------------------- pgbench_branches 1 pgbench_tellers 10 pgbench_accounts 100000 pgbench_history 0
Le nombre de lignes peut être augmenté en utilisant l'option -s (facteur d'échelle). L'option -F (facteur de remplissage) peut aussi être utilisée à ce moment.
Une fois la configuration exécutée, le test de performance peut être lancé avec une commande qui n'inclut pas l'option -i, c'est-à-dire :
pgbench [ options ] nom_base
Dans la plupart des cas, vous aurez besoin de quelques options pour que ce test soit réellement intéressant. Les options les plus importantes sont -c (nombre de clients), -t (nombre de transactions), -T (limite de temps) et -f (pour spécifier un script personnalisé). Voir ci-dessous pour une liste complète.
La documentation ci-après est répartie en trois sous-sections : des options différentes sont utilisées pour l'initialisation de la base de données, pour l'exécution des tests de performances, voire dans les deux cas.
pgbench comprend les options de la ligne de commande suivants :
Requis lorsqu'on veut utiliser le mode d'initialisation.
Crée les tables pgbench_accounts, pgbench_tellers et pgbench_branches avec le facteur de remplissage donné. La valeur par défaut est de 100.
N'exécute aucun VACUUM après l'initialisation.
Indique la latence moyenne par requête (temps d'exécution de la perspective du client) de chaque commande après la fin du test de performances. Voir ci-dessous pour les détails.
Multiplie le nombre de rangées par le facteur d'echelle. Par exemple, -s 100 créera 10,000,000 rangées dans la table pgbench_accounts. La valeur par défaut est de 1. Quand le facteur d'échelle est de 20000 ou plus, les colonnes utilisées pour les identifiants de compte (colonnes aid) basculeront vers le type bigint), pour qu'elles puissent contenir les identifiants en question.
Bascule les traces en mode silencieux, ne faisant qu'un message de progression toutes les cinq secondes. Les traces par défaut impriment un message toutes les 100000 lignes, ce qui affiche souvent de nombreuses lignes par seconde, tout spécialement sur du bon matériel.
Crée les clés étrangères entre les tables standards.
Crée les index dans le tablespace spécifié, plutôt que dans le tablespace par défaut.
Crée les tables dans le tablespace spécifié, plutôt que dans le tablespace par défaut.
Crée toutes les tables comme des tables non journalisées, plutôt que comme des tables ordinaires.
pgbench comprend les options de la ligne de commande suivants :
Nombre de clients simulés et donc le nombre de sessions concurrentes. La valeur par défaut est de 1.
Établit une nouvelle connexion pour chaque transaction, plutôt que le faire une fois par session. Ceci est utile pour mésurer les ressources consommées par la connexion.
Afficher la sortie de déboguage.
Définit une variable pouvant être utilisé par un script personalisé (voir plus bas). Plusieurs options -D peuvent être utilisées.
Lire le script de transaction à partir de fichier. Voir plus bas pour les détails. -N, -S et -f ne peuvent pas être utilisés en même temps.
Nombre de threads au sein de pgbench. L'utilisation de plus d'un thread peut être utile sur des machines multi-processeurs. Le nombre de client doit être un multiple du nombre de threads puisqu'on donne à chaque thread le même nombre de sessions clients à gérer. La valeur par défaut est de 1.
Écrire le temps pris par chaque transaction dans le fichier de log. Voir plus bas pour les détails.
Protocole à utiliser pour soumettre les requêtes au serveur :
simple : utiliser le protocole de requêtes simples.
extended : utiliser le protocole de requêtes étendues.
prepared: utiliser le protocole de requêtes étendues avec instructions préparées.
Le protocole par defaut est celui de requêtes simples. (Voir Chapitre 48, Protocole client/serveur pour plus d'information.)
Ne pas faire de vacuuming avant de lancer le test. Cette option est obligatoire si vous lancez un scenario de test personalisé qui n'inclut pas les tables standards pgbench_accounts, pgbench_branches, pgbench_history et pgbench_tellers.
Ne pas mettre à jour pgbench_tellers et pgbench_branches. Ceci évitera les problemes de mises à jour sur ces tables mais rendra les tests moins semblables à TPC-B.
Rapporter le facteur d'echelle spécifié dans la sortie de pgbench. Avec les tests intégrés par défaut, ceci n'est pas necessaie ; le facteur sera déduit en comptant les nombres de rangées dans la table pgbench_branches. Par contre, lors que vous testerez des benchmarks personalisés (avec l'option -f), le facteur rapporté sera de 1 sauf si cette option est utilisée.
Faire des tests à base de select uniquement plutôt que TPC-B.
Le nombre de transactions que chaque client doit jouer. Le défaut est de 10.
Lancer ce test autant de secondes, plutôt qu'un nombre fixe de transactions par clients. -t et -T ne peuvent pas être utilisés en même temps.
Faire un vacuum sur les quatre tables standard avant de lancer le test. Sans -n ou -v, pgbench fera un vacuum sur les tables pgbench_tellers et pgbench_branches et tronquera pgbench_history.
Longueur de l'intervalle d'agrégation (en secondes). Peut seulement être utilisée avec -l - avec cette option, la trace contient un résumé par intervalle (nombre de transactions, latence minimale et maximale, et deux champs supplémentaires utiles pour l'estimation de la variance).
Cette option n'est actuellement pas supportée sous Windows.
Taux d'échantillonnage, utilisé lors de l'écriture des données dans les traces, pour réduire la quantité de traces générées. Si cette option est fournie, seule la fraction de transactions indiquées est tracée. 1,0 signifie que toutes les transactions seront tracées, 0,05 signifie que seulement 5% des transactions seront tracées.
Rappelez-vous de prendre en compte le taux d'échantillonnage lors du traitement du fichier de traces. Par exemple, lors du calcul du nombre de transactions par seconde, vous aurez besoin de multiplier les nombres en concordance (par exemple avec un taux d'échantillonnage de 0,01, vous obtiendrez réellement un centième du nombre de transactions par seconde).
pgbench reconnait les options habituels suivantes de ligne de commande :
Le nom de machine du serveur base de données
Le numéro de port du serveur base de données
Le nom avec lequel se connecter
Affiche la version de pgbench, puis quitte.
Affiche l'aide sur les arguments en ligne de commande pgbench, puis quitte.
Le script de transaction par défaut exécute sept commandes :
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 indiquez -N, les étapes 4 et 5 ne sont pas inclus dans la transaction. Si vous indiquez -S, seul le SELECT est exécuté.
pgbench sait exécuter des scénarios personnalisés en remplaçant le script de transaction par défaut (décrit ci-dessus) avec un script de transaction lu à partir d'un fichier (option -f). Dans ce cas, une « transaction » compte en tant qu'une exécution du fichier. Vous pouvez même indiquer plusieurs scripts (avec plusieurs options -f), auquel cas un script est choisi au hasard à chaque fois qu'une session client exécute une nouvelle transaction.
Le fichier doit contenir une commande par ligne ; les commandes SQL multi-lignes ne sont pas acceptées. Les lignes vides et les lignes commençant par -- sont ignorées. Les lignes du fichier peuvent aussi contenir des « meta commandes », qui sont interprétées par pgbench lui-même, comme décrit ci-dessous.
Il existe une fonctionnalité de substitution de variables pour les fichiers. Les variables sont configurables par l'option -D en ligne de commande, comme expliqué ci-dessus, ou par les méta-commandes expliquées ci-dessous. En plus des variables pré-initialisées par les options -D, la variable scale est pré-initialisée avec le facteur d'échelle actuel. Une fois configurée, la valeur d'une variable peut être insérée dans une commande SQL en écrivant :nom_variable. Lors de l'exécution de plusieurs sessions clients, chaque session a son propre ensemble de variables.
Les méta-commandes du script commencent par un antislash (\). Les arguments d'une méta-commande sont séparés par des espaces blancs. Voici la liste des méta-commandes acceptées :
Initialise la variable varname avec une valeur entière calculée. Chaque operande est soit une constante entière soit une référence :nom_variable à une variable entière. L'operateur peut être +, -, * ou /.
Exemple :
\set ntellers 10 * :scale
Initialise la variable nom_variable à une valeur entière prise au hasard entre les limites min et max, limites inclues. Chaque limite peut être soit une constante entière soit une référence :nom_variable à une valeur entière.
Exemple :
\setrandom aid 1 :naccounts
Provoque un endormissement de l'exécution du script pour la durée indiquée en microsecondes (us), millisecondes (ms) ou secondes (s). Si l'unité est omise, alors ce seront par défaut des secondes. nombre peut être soit un entier soit une référence :nom_variable à un entier.
Exemple :
\sleep 10 ms
Configure la variable nom_variable avec le résultat de la commande shell commande. La commande doit renvoyer une valeur entière via sa sortie standard.
argument peut être soit une constante de type texte soit une référence :nom_variable à une variable de n'importe quel type. Si vous voulez utiliser argument en commençant avec un signe deux-points, vous devez ajouer un signe deux-points supplémentaires au début de argument.
Exemple :
\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
Idem à \setshell, mais le résultat est ignoré.
Exemple :
\shell command literal_argument :variable ::literal_starting_with_colon
En exemple, voici la définition complète d'une transaction style TPC-B :
\set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -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 permet à chaque itération de la transaction de référencer des lignes différentes, prises au hasard. (Cet exemple montre aussi pourquoi il est imporant que chaque session client ait ses propres variables -- sinon elles ne traiteraient pas des lignes différentes.)
Avec l'option -l mais sans l'option --aggregate-interval, pgbench écrit la durée prise par chaque transaction dans un fichier de traces. Le journal sera nommé pgbench_log.nnn, où nnn est le PID du processus pgbench. Si l'option -j vaut 2 ou plus, ce qui va créer plusieurs threads de travail, chacun d'entre eux aura son propre journal applicatif. Le premier utilise le même nom de fichier que s'il avait été seul. Les autres fichiers des autres travailleurs seront nommés pgbench_log.nnn.mmm, où mmm est un numéro séquentiel pour chaque travailleur et commençant à 1.
Le format de ce journal est :
client_id transaction_no time file_no time_epoch time_us
où time est la durée totale de la transaction en microsecondes, file_no identifie le script qui a été utilisé (utile quand plusieurs scripts sont indiqués avec -f) et time_epoch/time_us sont une date/heure au format epoch Unix et un décalage en microsecondes (convenable pour la création d'un horodatage ISO 8601 avec des secondes en fration) indiquant la date et heure de la fin de la transaction.
Voici un exemple de journal :
0 199 2241 0 1175850568 995598 0 200 2465 0 1175850568 998079 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663
Lors de l'exécution d'un test long sur du matériel qui peut gérer un grand nombre de transactions, les traces peuvent devenir très grosses. L'option --sampling-rate peut être utilisée pour ne tracer qu'un ensemble aléatoire de transactions.
Avec l'option --aggregate-interval, les traces utilisent un format un peu différent :
début_intervalle nombre_de_transactions somme_latence somme_latence_2 min_latence max_latence
où début_intervalle est le début de l'intervalle (horodatage au format UNIX epoch), nombre_de_transactions est le nombre de transactions dans cet intervalle, somme_latence est la somme des latences (pour que vous puissiez calculer la moyenne facilement). Les deux champs suivants sont utiles pour estimer la variances - somme_latence est une somme des latences et somme_latence_2 est une somme des latence puissance 2. Les deux derniers champs sont min_latence - la latence minimale dans cet intervalle, et max_latence - la latence maximale dans cet intervalle. Une transaction est comptée dans l'intervalle où elle a été validée.
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, bien que la trace simple (non agrégée) contient un index des fichiers de script personnalisés, la trace agrégée n'en contient pas. Du coup, si vous avez besoin de données par script, vous devez agréger les données vous-même.
Avec l'option -r, pgbench récupère le temps passé sur chaque requête exécutée par les clients. Il affiche ensuite la moyenne de ces valeurs, comme la latence de chaque requête, une fois que le test de performances est terminé.
Pour le script par défaut, la sortie ressemble à ceci :
starting vacuum...end. transaction type: TPC-B (sort of) 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 tps = 618.764555 (including connections establishing) tps = 622.977698 (excluding connections establishing) statement latencies in milliseconds: 0.004386 \set nbranches 1 * :scale 0.001343 \set ntellers 10 * :scale 0.001212 \set naccounts 100000 * :scale 0.001310 \setrandom aid 1 :naccounts 0.001073 \setrandom bid 1 :nbranches 0.001005 \setrandom tid 1 :ntellers 0.001078 \setrandom delta -5000 5000 0.326152 BEGIN; 0.603376 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.454643 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 5.528491 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 7.335435 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.371851 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.212976 END;
Si plusieurs fichiers de script sont donnés, les moyennes sont reportées séparément pour chaque fichier de script.
Notez que la récupération de cette information pour chaque requête exécutée ajoute une surcharge. Cela ralentira la vitesse d'exécution moyenne et diminuera d'autant le nombre de transactions par seconde calculé. Le ralentissement constaté varie significativement suivant la plateforme et le matériel. Comparer les valeurs moyennes avec et sans latence est une bonne façon de constater si la surcharge est significative ou non.
Il est très facile d'utiliser pgbench pour produire des nombres sans signification. Voici quelques lignes de conduite pour vous aider à obtenir des résultats intéressants.
En premier lieu, ne jamais croire tout test qui ne s'exécute que pendant quelques secondes. Utilisez l'option -t ou -T pour que le test dure plusieurs minutes pour rendre le bruit insignifiant. Dans certains cas, nous avez besoin de quelques heures pour obtenir des chiffres reproductibles. Exécuter le test plusieurs fois est une bonne idée pour savoir si vos résultats sont reproductibles.
Pour le scénario par défaut, style TPC-B, le facteur d'échelle à l'initialisation (-s) doit être au moins aussi important que le plus grand nombre de clients que vous souhaitez supporter (-c) ; sinon vous ne ferez que mesurer la contention des mises à jour. Il n'y a que -s lignes dans la table pgbench_branches, et chaque transaction veut en mettre une à jour, donc les valeurs -c supérieures à -s résulteront sans doute en beaucoup de transactions bloquées, en attente d'autres transactions.
Le scénario test par défaut est aussi assez sensible du moment où les tables ont été initialisées : une accumulation de lignes morts et d'espace vide dans les tables modifient les résultats. Pour comprendre les résultats, vous devez garder trace de nombre total de mises à jour et des moments où un VACUUM est exécuté. Si l'autovacuum est activé, cela peut causer des modifications non prévisibles dans les performances mesurées.
Une limite de pgbench est qu'il peut devenir lui-même le goulot d'étranglement lors de tentative de tests d'un grand nombre de sessions clients. Ceci peut se voir allégé en exécutant pgbench sur une autre machine que le serveur de bases de données, bien que la latence du réseau est essentielle. Il pourrait même être utile d'exécuter plusieurs instances pgbench en parallèle sur plusieurs machines client, pour le même serveur de bases de données.