Benchmarking de Base de Datos con pgbench y mysqlslap
La validación de rendimiento de base de datos requiere herramientas específicamente diseñadas para generar cargas de trabajo transaccionales realistas y medir respuesta del sistema. pgbench para PostgreSQL y mysqlslap para MySQL proporcionan métodos estándar de la industria para benchmarking de bases de datos, permitiendo planificación de capacidad y optimización de rendimiento. Esta guía cubre despliegue de ambas herramientas para análisis exhaustivo de rendimiento de base de datos.
Tabla de Contenidos
- pgbench para PostgreSQL
- Configuración de Carga de Trabajo de pgbench
- mysqlslap para MySQL
- Benchmarking SQL Personalizado
- Interpretación de Resultados
- Validación de Optimización de Rendimiento
- Benchmarking Comparativo
- Conclusión
pgbench para PostgreSQL
Instalación y Configuración de pgbench
# pgbench viene con PostgreSQL
psql --version
# Inicializar base de datos pgbench
createdb pgbench
# Generar datos de prueba (factor de escala 10 = 100,000 filas)
pgbench -i -s 10 pgbench
# Parámetros:
# -i: Inicializar (preparar tablas de prueba)
# -s: Factor de escala (determina volumen de datos)
# Verificar tablas generadas
psql pgbench -c "SELECT schemaname, tablename FROM pg_tables WHERE schemaname='public';"
# Ver tamaños de tabla
psql pgbench -c "SELECT tablename, pg_size_pretty(pg_relation_size(schemaname||'.'||tablename)) FROM pg_tables WHERE schemaname='public';"
Prueba Básica de pgbench
# Ejecutar benchmark OLTP básico (10 segundos)
pgbench -r pgbench
# La salida estándar muestra:
# TPS (Transacciones Por Segundo)
# Latencia promedio
# Latencia del percentil 90
# Parámetros de prueba extendida
pgbench -c 10 -j 4 -T 60 pgbench
# Parámetros explicados:
# -c 10: 10 clientes concurrentes
# -j 4: 4 hilos (uno por conexión)
# -T 60: Duración de la prueba de 60 segundos
# Ver tasas de transacciones
pgbench -r -R 1000 pgbench # Limitado en velocidad a 1000 TPS
Pruebas de Escalabilidad de pgbench
# Probar varios recuentos de clientes
for clients in 1 5 10 20 50; do
echo "=== $clients clients ==="
pgbench -c $clients -j $((clients/2)) -T 30 pgbench
done
# Prueba con conjunto de datos más grande
pgbench -i -s 100 pgbench # 1,000,000 filas
pgbench -c 20 -j 4 -T 60 pgbench
# Monitorear durante la prueba
# En terminal paralela:
watch -n 1 'psql pgbench -c "SELECT count_est FROM pgbench_stats;"'
Configuración de Carga de Trabajo de pgbench
Carga de Trabajo Personalizada de pgbench
# Crear script SQL personalizado
cat > ~/pgbench_custom.sql <<'EOF'
\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);
COMMIT;
EOF
# Ejecutar carga de trabajo personalizada
pgbench -f ~/pgbench_custom.sql -c 10 -j 4 -T 60 pgbench
Carga de Trabajo Pesada en Lectura
# Crear script de prueba de solo lectura
cat > ~/pgbench_readonly.sql <<'EOF'
\set aid random(1, 100000 * :scale)
BEGIN;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
SELECT * FROM pgbench_branches WHERE bid = :aid % 100;
COMMIT;
EOF
# Ejecutar carga de trabajo de lectura
pgbench -f ~/pgbench_readonly.sql -c 20 -j 4 -T 60 -r pgbench
mysqlslap para MySQL
Instalación y Configuración de mysqlslap
# mysqlslap viene con herramientas de cliente MySQL
mysql --version
# Prueba de generación automática básica
mysqlslap --auto-generate-sql --concurrency=10 --number-of-queries=1000
# Conectar a servidor MySQL específico
mysqlslap -h localhost -u root -p --auto-generate-sql --concurrency=10
# Parámetros:
# --auto-generate-sql: Generar SQL aleatorio
# --concurrency: Número de clientes
# --number-of-queries: Total de consultas a ejecutar
Generación de Carga de Trabajo de mysqlslap
# Generar carga de trabajo exhaustiva
mysqlslap \
--auto-generate-sql \
--auto-generate-sql-load-type=mixed \
--concurrency=5,10,15 \
--number-of-queries=5000 \
--engine=InnoDB \
-u root -p
# Tipos de carga de trabajo:
# read: Solo consultas SELECT
# write: INSERT/UPDATE/DELETE
# key: UPDATE con cláusula WHERE
# mixed: Combinación de todos los tipos
# Preservar datos de prueba entre ejecuciones
mysqlslap \
--create-schema=testdb \
--auto-generate-sql \
--preserve-schema-on-disconnect \
--concurrency=10 \
--number-of-queries=10000 \
-u root -p
Consultas Personalizadas de mysqlslap
# Crear script SQL personalizado
cat > ~/mysql_test.sql <<'EOF'
SELECT * FROM test_table WHERE id = @id;
INSERT INTO test_table (name, value) VALUES ('test', RAND());
UPDATE test_table SET value = RAND() WHERE id = @id;
DELETE FROM test_table WHERE id < 100;
EOF
# Ejecutar prueba personalizada
mysqlslap \
--concurrency=10 \
--iterations=10 \
--query=~/mysql_test.sql \
--create-schema=testdb \
-u root -p
# Múltiples archivos de consulta
mysqlslap \
--concurrency=10 \
--query=~/read_queries.sql \
--query=~/write_queries.sql \
-u root -p
Benchmarking SQL Personalizado
Pruebas de Optimización Específicas de Base de Datos
# PostgreSQL: Probar cambios de plan de consulta
cat > test_query_performance.sql <<'EOF'
EXPLAIN ANALYZE
SELECT * FROM large_table WHERE indexed_column = 'value';
-- Después de crear índice
CREATE INDEX idx_indexed_column ON large_table(indexed_column);
EXPLAIN ANALYZE
SELECT * FROM large_table WHERE indexed_column = 'value';
EOF
# Ejecutar antes y después de creación de índice
pgbench -f test_query_performance.sql pgbench
# MySQL: Probar con diferentes motores
cat > test_engine_performance.sql <<'EOF'
ALTER TABLE test_table ENGINE=InnoDB;
-- Ejecutar benchmark
-- Entonces:
ALTER TABLE test_table ENGINE=MyISAM;
-- Ejecutar de nuevo para comparación
EOF
Interpretación de Resultados
Entender Métricas de TPS
# Ejemplo de salida de pgbench:
# transaction type: TPC-B (sort of)
# scaling factor: 10
# number of clients: 10
# number of threads: 4
# number of transactions skipped: 0
# number of transactions processed: 6000
# number of failed transactions: 0
# latency average = 1.667 ms
# latency stddev = 2.551 ms
# latency min = 0.495 ms
# latency max = 45.829 ms
# latency p50 = 1.285 ms
# latency p95 = 3.456 ms
# latency p99 = 7.890 ms
# tps = 599.88 (including connections establishing)
# tps = 600.05 (excluding connections establishing)
# Interpretación:
# Mayor TPS = mejor rendimiento
# Menor latencia = mejor capacidad de respuesta
# Latencia consistente = rendimiento estable
Análisis de Latencia
# Crear script para analizar progresión de latencia
cat > analyze_latency_trend.sh <<'EOF'
#!/bin/bash
echo "time,avg_latency,p95_latency,p99_latency" > latency_trend.csv
for iteration in {1..10}; do
sleep 60 # Dejar que el sistema se estabilice
result=$(pgbench -c 20 -j 4 -T 60 pgbench 2>&1)
avg=$(echo "$result" | grep "average" | awk '{print $NF}')
p95=$(echo "$result" | grep "p95" | awk '{print $NF}')
p99=$(echo "$result" | grep "p99" | awk '{print $NF}')
echo "$(date +%H:%M:%S),$avg,$p95,$p99" >> latency_trend.csv
done
# Ver resultados
column -t -s, latency_trend.csv
EOF
chmod +x analyze_latency_trend.sh
./analyze_latency_trend.sh
Validación de Optimización de Rendimiento
Comparación Antes/Después de Optimización
# Prueba de línea base
pgbench -c 20 -j 4 -T 60 -r pgbench | tee baseline.txt
# Aplicar optimización (ajustar postgresql.conf)
# shared_buffers = 256MB
# effective_cache_size = 4GB
# work_mem = 20MB
# Recargar configuración
sudo systemctl restart postgresql
# Prueba post-optimización
pgbench -c 20 -j 4 -T 60 -r pgbench | tee after_tuning.txt
# Comparar resultados
echo "=== TPS Comparison ==="
grep "tps =" baseline.txt
grep "tps =" after_tuning.txt
echo "=== Latency Comparison ==="
grep "latency average" baseline.txt
grep "latency average" after_tuning.txt
Pruebas de Impacto de Configuración
# Prueba diferentes configuraciones de caché
for shared_buffers in "64MB" "256MB" "1GB"; do
# Actualizar postgresql.conf
sudo sed -i "s/^shared_buffers = .*/shared_buffers = $shared_buffers/" /etc/postgresql/*/main/postgresql.conf
# Reiniciar PostgreSQL
sudo systemctl restart postgresql
# Ejecutar prueba
echo "=== Testing shared_buffers=$shared_buffers ==="
pgbench -c 10 -j 4 -T 60 pgbench | grep "tps ="
done
Benchmarking Comparativo
Comparación de Base de Datos
# Comparar rendimiento de PostgreSQL vs MySQL
echo "=== PostgreSQL Benchmark ==="
pgbench -i -s 50 pgbench
pgbench -c 20 -j 4 -T 60 -r pgbench
echo "=== MySQL Benchmark ==="
mysql -u root -p -e "CREATE DATABASE mysqlslap_test;"
mysqlslap \
--auto-generate-sql \
--concurrency=20 \
--number-of-queries=100000 \
--engine=InnoDB \
-u root -p
Comparación de Versiones
# Probar diferentes versiones de PostgreSQL
# Instalar múltiples versiones:
# PostgreSQL 12, 13, 14, 15
# Para cada versión:
# Inicializar clúster, ejecutar benchmark
echo "=== PostgreSQL 14 ==="
/usr/lib/postgresql/14/bin/pgbench -i -s 50 pgbench_14
/usr/lib/postgresql/14/bin/pgbench -c 20 -j 4 -T 60 pgbench_14 | grep "tps ="
echo "=== PostgreSQL 15 ==="
/usr/lib/postgresql/15/bin/pgbench -i -s 50 pgbench_15
/usr/lib/postgresql/15/bin/pgbench -c 20 -j 4 -T 60 pgbench_15 | grep "tps ="
Conclusión
pgbench y mysqlslap proporcionan capacidades esenciales para validación de rendimiento de base de datos y optimización. Al establecer métricas de línea base antes de la optimización, las organizaciones cuantifican mejora a partir de cambios de configuración y actualizaciones de hardware. Entender percentiles de latencia y rendimiento de transacciones permite decisiones informadas sobre planificación de capacidad. El benchmarking regular detecta degradación de rendimiento por envejecimiento de hardware, fragmentación o configuraciones subóptimas. Ya sea validando nueva infraestructura de base de datos, evaluando actualizaciones de versión mayor o demostrando el valor de esfuerzos de optimización, las herramientas de benchmarking de base de datos siguen siendo indispensables para excelencia en ingeniería de base de datos.


