pgbench y mysqlslap son las herramientas de benchmarking que vienen incluidas con PostgreSQL y MySQL respectivamente. pgbench ejecuta una carga transaccional parecida a TPC-B y mide transacciones por segundo (TPS) y latencia; mysqlslap lanza consultas desde varios clientes concurrentes y mide cuánto tardan en completarse. En este tutorial usarás ambas en Ubuntu 24.04 para obtener una línea base, probar distintos niveles de concurrencia, ejecutar tus propias consultas y comprobar el efecto de un cambio de configuración.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM.
  • Un usuario no root con privilegios sudo.
  • Unos 5 GB libres en disco.
  • PostgreSQL 16 para la primera parte y MySQL 8.0 para la segunda. Puedes seguir solo la parte del motor que uses.

Paso 1: Instalar PostgreSQL y comprobar pgbench

Instala PostgreSQL desde los repositorios de Ubuntu. pgbench se instala junto con él:

sudo apt update
sudo apt install postgresql

Comprueba que el servicio está activo y que pgbench está disponible:

systemctl status postgresql --no-pager
pgbench --version
pgbench (PostgreSQL) 16.10 (Ubuntu 16.10-0ubuntu0.24.04.1)

Paso 2: Inicializar la base de datos de prueba

pgbench necesita sus propias tablas (pgbench_accounts, pgbench_branches, pgbench_tellers y pgbench_history). Crea una base de datos dedicada como usuario postgres:

sudo -u postgres createdb pgbench

Llena las tablas con -i (inicializar). El factor de escala -s fija el volumen: cada unidad son 100.000 filas en pgbench_accounts, unos 15 MB. Con -s 50 obtienes 5 millones de filas y unos 750 MB:

sudo -u postgres pgbench -i -s 50 pgbench
dropping old tables...
creating tables...
generating data (client-side)...
5000000 of 5000000 tuples (100%) done (elapsed 6.12 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done in 8.94 s (drop tables 0.00 s, create tables 0.01 s, client-side generate 6.25 s, vacuum 0.84 s, primary keys 1.84 s).

Comprueba el tamaño de la base de datos:

sudo -u postgres psql -d pgbench -c "SELECT pg_size_pretty(pg_database_size('pgbench'));"

Paso 3: Ejecutar el benchmark estándar de pgbench

Lanza la prueba por defecto durante 60 segundos con 10 clientes y 2 hilos de pgbench, mostrando el progreso cada 10 segundos:

sudo -u postgres pgbench -c 10 -j 2 -T 60 -P 10 pgbench
  • -c: clientes concurrentes, es decir, conexiones abiertas a la vez.
  • -j: hilos del propio pgbench que reparten esos clientes. Usa como máximo el número de vCPU.
  • -T: duración en segundos.
  • -P: intervalo del informe de progreso.
progress: 10.0 s, 1482.3 tps, lat 6.738 ms stddev 2.911, 0 failed
progress: 20.0 s, 1510.8 tps, lat 6.617 ms stddev 2.640, 0 failed
...
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 50
query mode: simple
number of clients: 10
number of threads: 2
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 89915
number of failed transactions: 0 (0.000%)
latency average = 6.672 ms
latency stddev = 2.781 ms
initial connection time = 21.305 ms
tps = 1498.712305 (without initial connection time)

Las cifras que debes anotar son tps (más alto es mejor) y latency average (más bajo es mejor). Si la desviación típica es grande comparada con la media, hay picos de latencia, normalmente por esperas de disco o bloqueos.

La transacción por defecto hace tres UPDATE, un SELECT y un INSERT, así que mide sobre todo escritura. Para una carga de solo lectura usa -S:

sudo -u postgres pgbench -S -c 10 -j 2 -T 60 pgbench

Paso 4: Medir cómo escala con la concurrencia

El número de clientes a partir del cual los TPS dejan de crecer indica la concurrencia útil del servidor. Repite la prueba con distintos valores:

for c in 1 4 8 16 32 64; do
  printf 'clientes=%s ' "$c"
  sudo -u postgres pgbench -c "$c" -j 2 -T 30 pgbench 2>/dev/null | grep '^tps'
done
clientes=1 tps = 412.550812 (without initial connection time)
clientes=4 tps = 1204.117320 (without initial connection time)
clientes=8 tps = 1471.908156 (without initial connection time)
clientes=16 tps = 1552.360479 (without initial connection time)
clientes=32 tps = 1538.902214 (without initial connection time)
clientes=64 tps = 1490.221730 (without initial connection time)

En este ejemplo el rendimiento se estanca en torno a 16 clientes. Por encima solo aumenta la latencia, algo a tener en cuenta al dimensionar el pool de conexiones de la aplicación. PostgreSQL admite 100 conexiones por defecto (max_connections), así que no pases de ese valor sin ajustarlo.

Paso 5: Probar tus propias consultas con pgbench

pgbench puede ejecutar un script SQL propio con -f. Las variables se definen con \set y se usan como :nombre; :scale contiene el factor de escala. Crea un script que simula lecturas por clave primaria:

nano ~/select-account.sql
\set aid random(1, 100000 * :scale)
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

pgbench se ejecuta como postgres, que no puede leer tu directorio personal, así que pásale el script por una tubería:

cat ~/select-account.sql | sudo -u postgres pgbench -f /dev/stdin -c 16 -j 2 -T 30 -M prepared pgbench

-M prepared usa sentencias preparadas, como hacen la mayoría de controladores de aplicación, y suele dar más TPS que el modo simple por defecto. Para probar consultas de tu aplicación, crea sus tablas en esta base de datos y cambia el SELECT por las consultas reales.

Paso 6: Comparar antes y después de un ajuste

El uso más valioso de pgbench es cuantificar un cambio. Guarda primero una línea base:

sudo -u postgres pgbench -c 16 -j 2 -T 120 pgbench | tee ~/pgbench-antes.txt

Como ejemplo, sube shared_buffers desde los 128 MB por defecto a un 25 % de la RAM. En un servidor de 4 GB, edita el archivo de configuración:

sudo nano /etc/postgresql/16/main/postgresql.conf

Busca la línea shared_buffers y déjala así:

shared_buffers = 1GB

shared_buffers solo se aplica al reiniciar el servicio:

sudo systemctl restart postgresql
sudo -u postgres psql -c "SHOW shared_buffers;"

Repite exactamente la misma prueba y compara:

sudo -u postgres pgbench -c 16 -j 2 -T 120 pgbench | tee ~/pgbench-despues.txt
grep -H -E '^tps|latency average' ~/pgbench-antes.txt ~/pgbench-despues.txt

Ejecuta cada prueba al menos dos o tres veces. Diferencias de un 2-3 % entre ejecuciones son ruido; no saques conclusiones de ellas.

Paso 7: Instalar MySQL y comprobar mysqlslap

Pasa ahora a MySQL. Instala el servidor, que incluye el cliente y mysqlslap:

sudo apt install mysql-server
mysqlslap --version
mysqlslap  Ver 8.0.43-0ubuntu0.24.04.1 for Linux on x86_64 ((Ubuntu))

En Ubuntu, el usuario root de MySQL se autentica por socket Unix, así que puedes ejecutar mysqlslap con sudo sin contraseña.

Paso 8: Ejecutar una carga automática con mysqlslap

mysqlslap puede generar tablas y consultas por sí mismo. Esta orden crea una tabla temporal, lanza una carga mixta de lecturas y escrituras con 10, 50 y 100 clientes, repite cada nivel tres veces y borra el esquema al terminar:

sudo mysqlslap --auto-generate-sql \
  --auto-generate-sql-load-type=mixed \
  --auto-generate-sql-add-autoincrement \
  --number-int-cols=4 --number-char-cols=4 \
  --concurrency=10,50,100 --iterations=3 \
  --number-of-queries=20000 --engine=innodb
Benchmark
	Running for engine innodb
	Average number of seconds to run all queries: 1.842 seconds
	Minimum number of seconds to run all queries: 1.790 seconds
	Maximum number of seconds to run all queries: 1.911 seconds
	Number of clients running queries: 10
	Average number of queries per client: 2000

Benchmark
	Running for engine innodb
	Average number of seconds to run all queries: 1.503 seconds
	...
	Number of clients running queries: 50
	Average number of queries per client: 400

El total de consultas se reparte entre los clientes, así que cada bloque ejecuta el mismo trabajo. Si el tiempo medio baja al subir la concurrencia, el servidor aprovecha el paralelismo; si sube, está saturado. Otros tipos de carga para --auto-generate-sql-load-type son read, write, key y update.

Paso 9: Probar tus propias consultas con mysqlslap

Las consultas generadas son sintéticas. Para algo más representativo, define tu propio esquema y tus consultas. Crea el archivo de creación de datos:

nano ~/slap-create.sql
CREATE TABLE orders (id INT AUTO_INCREMENT PRIMARY KEY, customer_id INT NOT NULL, total DECIMAL(10,2) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_customer (customer_id));
INSERT INTO orders (customer_id, total) VALUES (1, 19.90), (2, 45.00), (3, 12.50), (1, 99.99), (4, 7.25);
INSERT INTO orders (customer_id, total) SELECT FLOOR(1 + RAND() * 1000), ROUND(RAND() * 200, 2) FROM orders a, orders b, orders c, orders d;

Crea el archivo con las consultas que se lanzarán en cada iteración:

nano ~/slap-query.sql
SELECT * FROM orders WHERE customer_id = 42;
SELECT customer_id, SUM(total) FROM orders GROUP BY customer_id ORDER BY 2 DESC LIMIT 10;
INSERT INTO orders (customer_id, total) VALUES (42, 25.00);

Ejecuta la prueba. --delimiter indica cómo separar las sentencias dentro de los archivos:

sudo mysqlslap --create-schema=slaptest \
  --create=$HOME/slap-create.sql --query=$HOME/slap-query.sql \
  --delimiter=";" --concurrency=20 --iterations=5

mysqlslap crea el esquema slaptest, ejecuta las consultas desde 20 clientes cinco veces y lo elimina al final. Si quitas el índice idx_customer del CREATE TABLE y repites, verás cómo cambia el tiempo medio: es una forma rápida de medir el impacto de un índice.

Paso 10: Limpiar

Elimina la base de datos de pgbench cuando termines:

sudo -u postgres dropdb pgbench

mysqlslap ya elimina sus esquemas al terminar. Comprueba que no queda ninguno:

sudo mysql -e "SHOW DATABASES;"

Solución de problemas

  • pgbench: error: connection to server on socket ... failed: FATAL: role "your_user" does not exist: estás ejecutando pgbench con tu usuario. Usa sudo -u postgres como en los ejemplos.
  • FATAL: sorry, too many clients already: -c supera max_connections. Reduce el número de clientes o sube el límite en postgresql.conf.
  • mysqlslap: Error when connecting to server: 1045 Access denied for user 'your_user'@'localhost': ejecuta mysqlslap con sudo para autenticarte como root por socket, o indica un usuario con -u y -p.
  • Too many connections en mysqlslap: la concurrencia supera max_connections de MySQL (151 por defecto).

Conclusión

Con pgbench has obtenido TPS y latencia de PostgreSQL, has visto hasta dónde escala con la concurrencia y has medido el efecto de un ajuste de shared_buffers. Con mysqlslap has probado MySQL con carga automática y con tus propias consultas. Como siguientes pasos, puedes medir el disco que hay debajo con fio, ejecutar sysbench oltp_read_write para una comparación OLTP más completa en MySQL, o revisar las consultas lentas reales con pg_stat_statements.