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.
Importanteno lances estas pruebas contra una base de datos en producción. Generan carga intensa y pgbench crea y modifica sus propias tablas. Usa un servidor de pruebas o una base de datos dedicada.
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'));"
Consejosi quieres medir el disco y no solo la memoria, elige un factor de escala cuyo tamaño supere la RAM del servidor. Si la base de datos cabe en
shared_buffersy en la caché del sistema, estarás midiendo sobre todo CPU.
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.
Notamysqlslap mide el tiempo total de un lote de consultas, no TPS ni percentiles de latencia. Para una carga OLTP comparable a pgbench en MySQL, usa
sysbench oltp_read_write.
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. Usasudo -u postgrescomo en los ejemplos.FATAL: sorry, too many clients already:-csuperamax_connections. Reduce el número de clientes o sube el límite enpostgresql.conf.mysqlslap: Error when connecting to server: 1045 Access denied for user 'your_user'@'localhost': ejecuta mysqlslap consudopara autenticarte comorootpor socket, o indica un usuario con-uy-p.Too many connectionsen mysqlslap: la concurrencia superamax_connectionsde 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.
