Este documento presenta una charla sobre optimización del rendimiento con MySQL. La charla cubre temas como la arquitectura de MySQL, incluyendo los motores de almacenamiento MyISAM e InnoDB, y técnicas para optimizar consultas como el uso adecuado de índices y cachés. El objetivo es ayudar a los desarrolladores a mejorar el rendimiento de sus aplicaciones basadas en MySQL.
1. Optimización del rendimiento con MySQL ( LSWC Noviembre 2011)
Víctor Jiménez Cerrada <vjimenez@warp.es>
@capitangolo
http://slideshare.net/capitangolo
Bienvenidos a "Optimización del rendimiento con MySQL".
Soy Víctor Jiménez y seré vuestro ponente para hoy.
2. Trabajo en Warp Networks S.L. http://www.warp.es
Donde nos dedicamos a varias cosas, entre ellas, formación y consultoría
MySQL
3. MySQL Training partner since 2006
Sun Microsystem Training partner 2009-2010
Oracle partner since 2010
Hemos sido partners de MySQL desde 2006
y en esta charla voy a compartir parte de la experiencia que hemos
obtenido desde entonces. Vamos a hablar de optimización del
rendimiento con MySQL
4. Agenda
5" 1- Introducción. ¿Por qué optimizar?
15" 2- Arquitectura de MySQL
20" 3- Optimización de consultas
… 4- Ruegos y Preguntas
5. 1 - Introducción ¿Por Qué optimizar?
2- Arquitectura de MySQL
3- Optimización de consultas
4- Ruegos y Preguntas
6. 1 - Introducción ¿Por Qué optimizar?
Desarrollamos nuestras apps web sin importarnos mucho el rendimiento.
Cuando nuestra web tiene éxito y se convierte en la gallina de los huevos
de oro, tenemos más solicitudes, y si no tenemos cuidado…
7. 1 - Introducción ¿Por Qué optimizar?
… nuestro servidor se cuelga.
A esto se le llama morir de éxito.
8. 1 - Introducción ¿Por Qué optimizar?
Pasos para no morir de éxito
Optimizar la aplicación
Optimizar la base de datos
Escalar
9. 1 - Introducción ¿Por Qué optimizar?
Optimización
Hacer más con lo mismo
Objetivo: Aumentar Consultas / segundo
¿Cómo?: Menor tiempo de ejecución
10. 1 - Introducción ¿Por Qué optimizar?
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Tenemos una consulta que tarda 2,5 segundos en ejecutarse si se ejecuta
sola.
Pero lo normal es que esa consulta se ejecute en varios procesos en
paralelo.
11. 1 - Introducción ¿Por Qué optimizar?
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Tenemos una consulta que tarda 2,5 segundos en ejecutarse si se ejecuta
sola.
Pero lo normal es que esa consulta se ejecute en varios procesos en
paralelo.
12. 1 - Introducción ¿Por Qué optimizar?
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Dado que la máquina tiene más recursos ocupados, es posible que tarde
más en ejecutarse.
En este caso, se ha ejecutado la consulta cinco veces en paralelo, cada
una un segundo más tarde que la anterior.
13. 1 - Introducción ¿Por Qué optimizar?
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Dado que la máquina tiene más recursos ocupados, es posible que tarde
más en ejecutarse.
En este caso, se ha ejecutado la consulta cinco veces en paralelo, cada
una un segundo más tarde que la anterior.
14. 1 - Introducción ¿Por Qué optimizar?
C=5
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
En un momento se están ejecutando 5 consultas a la vez.
El servidor necesita poder soportar estos picos.
15. 1 - Introducción ¿Por Qué optimizar?
C max = 1
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Si optimizamos esas consultas para que tarden medio segundo...
16. 1 - Introducción ¿Por Qué optimizar?
C max = 1
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
... sólo se ejecuta una consulta cada vez.
Reduciendo el nivel de concurrencia que tiene que soportar el servidor.
18. 1 - Introducción ¿Por Qué optimizar?
Más información
http://www.slideshare.net/capitangolo/no-mueras-de-exito
Dejando muchos más recursos libres.
19. 1- Introducción. ¿Por qué optimizar?
2 - Arquitectura MySQL
3- Optimización de consultas
4- Ruegos y Preguntas
20. 2 - Arquitectura MySQL
Arquitectura Cliente - Servidor
mysqld mysql
mysqld-nt Workbench
PHP My Admin
…
myisamchk
myisampack
MySQL tiene una arquitectura cliente servidor.
Aunque hay algunos programas 'ninjas' que acceden directamente a los
datos.
21. 2 - Arquitectura MySQL
Uso de Disco
/usr/local/mysql
test
table.frm
world
City.frm
Country.frm
CountryLanguage.frm
Hostname.pid
Hostname.err
En disco guarda tablas, logs y archivos de estado.
22. 2 - Arquitectura MySQL
Uso de Memoria
Thread Cache
Buffers y Cachés
Tablas en memoria
Tablas temporales
Buffers de cliente
23. 2 - Arquitectura MySQL
Uso de Memoria
Por Instancia
Reservado en el arranque del servidor
Compartido para todos los usuarios
Query Cache
Key Cache
InnoDB Buffer Pool
Por Sesión
Reservado por cada conexión
Principalmente para gestionar los resultados
sort_buffer
join_buffer
read_buffer
Hay que tener cuidado al configurar las variables de sesión.
20MB de sort_buffer x 100 conexiones = 2GB de memoria
24. 2 - Arquitectura MySQL
Arquitectura interna
API C Subsistemas
Intérprete Funciones base
Query
Hilos
Optimizador
Cache
Buffers y cachés
Executador
Red
Motores Logs
MyISAM InnoDB Acceso y Permisos
Memory CSV
25. 2 - Arquitectura MySQL
Motores de Almacenamiento
Gestionan la persistencia y recuperación de los datos
Configuración a nivel de Tabla
Oficiales:
MyISAM Motor por defecto en MySQL 5.0
InnoDB Motor por defecto en MySQL 5.5
Memory
Archive
Blackhole
CSV
…
De terceros:
solidDB Nitro
InfoBrigth PBXT
27. 2 - Arquitectura MySQL » MyISAM
MyISAM
Características
Formatos de fila
Bloqueos
Key Cache
Consejos
Merge
28. 2 - Arquitectura MySQL » MyISAM
Características de MyISAM (I)
/usr/local/mysql
world
City.frm
City.MYD
City.MYI
MyISAM guarda la información en dos archivos
.MYD(ata) y .MYI(ndex)
29. 2 - Arquitectura MySQL » MyISAM
Características de MyISAM (II)
No soporta transacciones
Bloqueos a nivel de tabla
Para un backup binario, copiar:
.frm
.MYD
.MYI
Un backup binario es portable
30. 2 - Arquitectura MySQL » MyISAM
Características de MyISAM (III)
Compresión de índices
prefijos en índices de tipo texto
Fulltext
ALTER TABLE table ADD FULLTEXT(column1, column2)
SELECT […] WHERE MATCH (column1, column2) AGAINST ('TEXT');
Concurrent inserts
concurrent_insert = 0 | 1 | 2
R-Tree index
Datos Geoposicionados (GIS)
31. 2 - Arquitectura MySQL » MyISAM
¿Cuándo usar MyISAM?
Aplicaciones de sólo lectura
Aplicaciones con poca concurrencia
Búsquedas de texto
Escaneos de tabla
Carga masiva de datos
Almacenamiento masivo de datos (datawarehousing)
32. 2 - Arquitectura MySQL » MyISAM
¿Cuándo NO usar MyISAM?
Almacenamiento Confiable y a prueba de caídas
Recuperación automática y rápida (HA)
Alta concurrencia
Bloqueos prolongados
Integridad Referencial
Transacciones
33. 2 - Arquitectura MySQL » MyISAM
Bloqueos MyISAM (I)
Bloqueo a nivel de tabla
Problemático cuando hay concurrencia
34. 2 - Arquitectura MySQL » MyISAM
Bloqueos MyISAM (II) - Consultas lentas
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Los select obtienen bloqueo de lectura compartido.
El insert solicita un bloqueo exclusivo de escritura.
Todos los demás selects posteriores esperan a que el insert libere el
bloqueo.
Hasta que el primer select termina, no se terminan de ejecutar las demás
consultas.
¡¡¡LLegamos a tener concurrencia 7!!!
35. 2 - Arquitectura MySQL » MyISAM
Bloqueos MyISAM (II) - Consultas lentas
SELECT x FROM tabla …
SELECT x FROM tabla
INSERT INTO tabla …
SELECT x FROM tabla …
SELECT x FROM tabla …
SELECT x FROM tabla …
SELECT x FROM tabla …
SELECT …
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Los select obtienen bloqueo de lectura compartido.
El insert solicita un bloqueo exclusivo de escritura.
Todos los demás selects posteriores esperan a que el insert libere el
bloqueo.
Hasta que el primer select termina, no se terminan de ejecutar las demás
consultas.
¡¡¡LLegamos a tener concurrencia 7!!!
36. 2 - Arquitectura MySQL » MyISAM
Bloqueos MyISAM (II) - Consultas lentas
SELECT …
SELECT …
INSERT …
SELECT …
SELECT …
SELECT …
SELECT …
SELECT …
0s 1s 2s 3s 4s 5s 6s 7s 8s 9s
Si optimizamos el primer select, los bloqueos bajan exponencialmente.
Concurrencia 4
37. 2 - Arquitectura MySQL » MyISAM
Bloqueos MyISAM (III) - Soluciones
concurrent_inserts
Las inserciones se realizan al final del archivo de datos.
SELECT HIGH PRIORITY
INSERT LOW PRIORITY
INSERT DELAYED
Se almacenan en un buffer, que va insertando cuando la tabla está libre.
38. 2 - Arquitectura MySQL » MyISAM
Key Cache (I)
Caché para índices MyISAM
key_buffer_size > 0
En MyISAM existe una caché de claves
39. 2 - Arquitectura MySQL » MyISAM
Key Cache (II) - Monitorización
key_reads / key_read_requests < 1%
key_blocks_not_flushed
key_blocks_used
key_blocks_unused
key_read_requests
key_reads
key_writes_requests
key_writes
Hay que configurar la caché de claves para que quepan todas las claves
en memoria.
42. 2 - Arquitectura MySQL » InnoDB
Características de InnoDB (I): Almacenamiento
/usr/local/mysql
test
table.frm
ibdata1
ib_logfile0
ib_logfile1
InnoDB guarda toda la información de todas las tablas en el tablespace.
Archivo ibdata
43. 2 - Arquitectura MySQL » InnoDB
Características de InnoDB (II): Files per table
innodb_file_per_table
/usr/local/mysql
test
table.frm
table.ibd
ibdata1
ib_logfile0
ib_logfile1
Si configuramos innodb_file_per_table tenemos un sub-espacio de tabla
por cada tabla
Archivo .ibd
El espacio de tabla sigue conteniendo información de cada tabla, es
necesario.
44. 2 - Arquitectura MySQL » InnoDB
Características de InnoDB (III)
Transacciones full ACID
Bloqueo a nivel de fila
El bloqueo se realiza en la PK
Buscando rangos, se bloquean también los huecos
Bloqueo a nivel de tabla
Cachea tanto índices como datos
46. 2 - Arquitectura MySQL » InnoDB
Transacciones (II)
Isolation Levels:
READ UNCOMMITED + CONCURRENCIA
READ COMMITED -
REPEATABLE READ -
SERIALIZABLE AISLAMIENTO +
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED
Podemos configurar el Nivel de aislamiento para mejorar el rendimiento
si no necesitamos tanta integridad en los datos.
47. 2 - Arquitectura MySQL » InnoDB
InnoDB Buffers (I)
Buffer Pool
MYSQL SERVER
Caché de datos e índices
Log Buffer
Log de transacciones
logfiles
LOG BUFFER
Log de transacciones BUFFER POOL
Redo log
ibdata commit checkpoints
& checkpoints
Diccionario de datos
Undo log
ib_logfiles ibdata
48. 2 - Arquitectura MySQL » InnoDB
InnoDB Buffers (II): Configuración
innodb_flush_log_at_trx_commit
Controla cómo el commit dispara el flush del log a disco
innodb_buffer_pool_size
80% de la memoria
Cuanto más grande, más datos se cachean
innodb_log_buffer_size
Un mayor tamaño permite que las transacciones grandes no tengan que escribir
a disco.
innodb_log_file_size
Un mayor tamaño de logfile:
reduce el tiempo entre checkpoints
aumenta el tiempo de recuperación
49. 2 - Arquitectura MySQL » InnoDB
Índices InnoDB
PK Index
PK PK PK Index Index Index
PK Index
En InnoDB, la clave primaria direcciona directamente a la tabla.
El resto de claves, direccionan a la clave primaria.
El resto de claves también incluyen la clave primaria.
50. 2 - Arquitectura MySQL » InnoDB
Consejos (I)
Usar claves primarias pequeñas (Enteros)
Cargar datos ordenados por clave primaria
Indexar prefijos (No hay compresión de índices)
51. 2 - Arquitectura MySQL » InnoDB
Consejos (II)
innodb_additional_mem_pool_size
innodb_autoextend_increment
innodb_thread_concurrency
SHOW ENGINE INNODB STATUS
52. 1- Introducción. ¿Por qué optimizar?
2- Arquitectura de MySQL
3 - Optimización de consultas
4- Ruegos y Preguntas
54. 3 - Optimización de consultas » Query Cache
Funcionamiento de la Query Cache (I)
MySQL server
Query Cache
Parse
Optimization
Execution
MyISAM InnoDB Memory
Tablas
Si activamos la Query Cache,
la primera vez que ejecutemos la consulta seguirá los mismos pasos.
Con un paso adicional, a la vez que se devuelven los datos al usuario, se
guarda una copia en la caché de consultas.
55. 3 - Optimización de consultas » Query Cache
Funcionamiento de la Query Cache (I)
SELECT
result
MySQL server
Query Cache
Parse
Optimization
Execution
MyISAM InnoDB Memory
Tablas
Si activamos la Query Cache,
la primera vez que ejecutemos la consulta seguirá los mismos pasos.
Con un paso adicional, a la vez que se devuelven los datos al usuario, se
guarda una copia en la caché de consultas.
56. 3 - Optimización de consultas » Query Cache
Funcionamiento de la Query Cache (I)
SELECT
result
MySQL server
SELECT result
Query Cache
Parse
Optimization
Execution
MyISAM InnoDB Memory
Tablas
Si activamos la Query Cache,
la primera vez que ejecutemos la consulta seguirá los mismos pasos.
Con un paso adicional, a la vez que se devuelven los datos al usuario, se
guarda una copia en la caché de consultas.
57. 3 - Optimización de consultas » Query Cache
Funcionamiento de la Query Cache (II)
SELECT
result
MySQL server
SELECT result
Query Cache
Parse
Optimization
Execution
MyISAM InnoDB Memory
Tablas
La próxima vez que se ejecute la misma consulta,
se obtendrán los datos diréctamente de la cache.
Lo que es un proceso casi instantáneo.
58. 3 - Optimización de consultas » Query Cache
Funcionamiento de la Query Cache (III)
UPDATE
MySQL server
Query Cache
Parse
Optimization
Execution
MyISAM InnoDB Memory
Tablas
¿Estos datos están siempre actualizados?
Sí, porque si se modifican los datos subyacentes, la caché se limpia.
60. 3 - Optimización de consultas » Query Cache
Monitorizar la Query Cache (I)
SET GLOBAL query_cache_size = 4 * 1024 * 1024;
SHOW GLOBAL STATUS LIKE 'qcache%';
+-------------------------+---------+
| Variable_name | Value |
+-------------------------+---------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 3555808 |
| Qcache_hits | 460 |
| Qcache_inserts | 173 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 37 |
| Qcache_queries_in_cache | 173 |
| Qcache_total_blocks | 366 |
+-------------------------+---------+
61. 3 - Optimización de consultas » Query Cache
Monitorizar la Query Cache (II)
SET GLOBAL query_cache_size = 4 * 1024 * 1024;
SHOW GLOBAL STATUS LIKE 'qcache%';
+-------------------------+---------+
| Variable_name | Value |
+-------------------------+---------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 3555808 |
| Qcache_hits | 460 |
| Qcache_inserts | 173 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 37 |
| Qcache_queries_in_cache | 173 |
| Qcache_total_blocks | 366 |
+-------------------------+---------+
62. 3 - Optimización de consultas » Query Cache
Monitorizar la Query Cache (III)
Uso = Qcache_hits / (Qcache_hits + COM_select)
SHOW GLOBAL STATUS LIKE 'Qcache_hits';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Qcache_hits | 460 |
+---------------+-------+
SHOW GLOBAL STATUS LIKE 'COM_select';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select | 334 |
+---------------+-------+
64. 3 - Optimización de consultas » mysqlslap
mysqlslap
$ mysqlslap [opciones]
opciones:
-i
-c
--create-schema
-q
otras opciones:
--user --password --host --port --socket
ejemplo:
$ mysqlslap -i 10 -c 2 --create-schema=test -q test.sql
mysqlslap permite realizar benchmarking básico de MySQL
65. 3 - Optimización de consultas » mysqlslap
salida de mysqlslap
$ mysqlslap -i 10 -c 2 --create-schema=test -q test.sql
Benchmark
Average number of seconds to run all queries: 51.776 seconds
Minimum number of seconds to run all queries: 51.776 seconds
Maximum number of seconds to run all queries: 51.776 seconds
Number of clients running queries: 2
Average number of queries per client: 239
$ mysqlslap -i 10 -c 2 --create-schema=test -q test.sql --csv=test.csv
$ cat test.csv
,mixed,51.776,51.776,51.776,2,239
66. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test
Datos
similares a los de producción
Consultas
similares a las de producción
suficiente cantidad
claves desordenadas
Servidor MySQL
Exclusivo para el test
Resultados
Leer con cuidado
67. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test: (I) Datos
> CREATE TABLE CityHuge LIKE City;
> INSERT INTO CityHuge
SELECT NULL, Name, CountryCode, District, Population
FROM City;
> INSERT INTO CityHuge
SELECT NULL, Name, CountryCode, District, Population
FROM CityHuge;
> SELECT COUNT(*) FROM CityHuge;
+----------+
| COUNT(*) |
+----------+
| 1044224 |
+----------+
Podemos crear tablas grandes insertando los datos de esa misma tabla
en sí misma.
68. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test: (II) Consultas
Logs
general
consultas lentas
Podemos hacer suites de test a partir de consultas SQL
69. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test: (II) Consultas
Logs
general
consultas lentas
SQL
$ mysql world -N --batch -e
"SELECT CONCAT(
'SELECT ID FROM CityHuge WHERE CountryCode="', code, '";')
FROM Country" > test.sql
Podemos hacer suites de test a partir de consultas SQL
70. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test: (III) Servidor MySQL
Exclusivo para el test
Configuración similar a producción
Limpiar cachés
Desactivar la Query Cache
71. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test: (IV) Resultados
Una diferencia de un 10% no es representativa
Test A : 5,45 s
6
Test B : 5,95 s
4,5
3
1,5
0
A B
72. 3 - Optimización de consultas » mysqlslap
Preparar una suite de test: (V) Resultados
En producción se ejecutan consultas de varios tipos mezcladas:
Test A (5 selects tabla 1) : 0,11 s
Test B (5 selects tabla 2) : 45 s
Test C (400 inserts en tablas 1 y 2) : 15 s
Test D ( A + B + C intercalados) : 153s
A
B
C
A+B+C
D
0 40 80 120 160
El test D tarda ¡¡3 veces más!!
No hay que fijarse en el valor absoluto, en producción no tardará eso.
Hay que fijarse en el porcentaje de mejora entre una opción y otra.
74. 3 - Optimización de consultas » EXPLAIN
EXPLAIN
EXPLAIN SELECT id FROM City WHERE Population > 1000000G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: City
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
Extra: Using where
Explain informa de cómo va a ejecutar MySQL una consulta.
75. 3 - Optimización de consultas » EXPLAIN
ALTER TABLE City ADD INDEX (Population);
ALTER TABLE City ADD INDEX `pop_code`(Population, CountryCode);
EXPLAIN SELECT Name
FROM City
WHERE CountryCode = 'ESP' AND Population > 1000000G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: City
type: range
possible_keys: Population,pop_code
key: Population
key_len: 4
ref: NULL
rows: 238
Extra: Using where
76. 3 - Optimización de consultas » EXPLAIN
ALTER TABLE City ADD INDEX (Population);
ALTER TABLE City ADD INDEX `pop_code`(Population, CountryCode);
EXPLAIN SELECT Name
FROM City
WHERE CountryCode = 'ESP' AND Population > 1000000G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: City
type: range
possible_keys: Population,pop_code
key: Population
key_len: 4
ref: NULL
rows: 238
Extra: Using where
77. 3 - Optimización de consultas » EXPLAIN
ALTER TABLE City ADD INDEX (Population);
ALTER TABLE City ADD INDEX `pop_code`(Population, CountryCode);
EXPLAIN SELECT Name
FROM City
WHERE CountryCode = 'ESP' AND Population > 1000000G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: City
type: range
possible_keys: Population,pop_code
key: Population
key_len: 4
ref: NULL
rows: 238
Extra: Using where
78. 3 - Optimización de consultas » EXPLAIN
ALTER TABLE City ADD INDEX (Population);
ALTER TABLE City ADD INDEX `pop_code`(Population, CountryCode);
EXPLAIN SELECT Name
FROM City
WHERE CountryCode = 'ESP' AND Population > 1000000G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: City
type: range
possible_keys: Population,pop_code
key: Population
key_len: 4
ref: NULL
rows: 238
Extra: Using where
79. 3 - Optimización de consultas » EXPLAIN
> EXPLAIN > EXPLAIN
SELECT * SELECT id
FROM City FROM City
WHERE ID = '345'G WHERE ID = '345'G
******** 1. row *********** ******** 1. row ***********
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: City table: City
type: const type: const
possible_keys: PRIMARY possible_keys: PRIMARY
key: PRIMARY key: PRIMARY
key_len: 4 key_len: 4
ref: const ref: const
rows: 1 rows: 1
Extra: Extra: Using index
80. 3 - Optimización de consultas » EXPLAIN
> EXPLAIN > EXPLAIN
SELECT * SELECT id
FROM City FROM City
WHERE ID = '345'G WHERE ID = '345'G
******** 1. row *********** ******** 1. row ***********
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: City table: City
type: const type: const
possible_keys: PRIMARY possible_keys: PRIMARY
key: PRIMARY key: PRIMARY
key_len: 4 key_len: 4
ref: const ref: const
rows: 1 rows: 1
Extra: Extra: Using index
Seleccionar sólo las columnas necesarias permite que:
A veces los datos puedan leerse sólo de los índices (memoria).
Se lean menos datos de disco en el resto de casos.
81. 3 - Optimización de consultas » EXPLAIN
> EXPLAIN > EXPLAIN
SELECT COUNT(id) SELECT COUNT(*)
FROM City FROM City
WHERE CountryCode = 'ESP'G WHERE CountryCode = 'ESP'G
150,0
112,5
c i COUNT(id) COUNT(*)
75,0 1 5 29,974 3,837
2 5 31,862 6,009
37,5
4 5 63,253 10,087
8 5 125,721 19,412
0
1 2 4 8
COUNT(id) COUNT(*)
En este caso, lo que ocurre es que COUNT(id) cuenta
el número de filas cuyo id es != NULL.
Para ello tiene que comprobar valor a valor.
82. 3 - Optimización de consultas » EXPLAIN
EXPLAIN
SELECT City.Name, Country.Name
FROM City, Country
WHERE Country.Code = City.CountryCode
AND Country.Name="Spain"G
*********** 1. row ********** *********** 2. row **********
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: City table: Country
type: ALL type: eq_ref
possible_keys: NULL possible_keys: PRIMARY
key: NULL key: PRIMARY
key_len: NULL key_len: 3
ref: NULL ref: world.City.CountryCode
rows: 4079 rows: 1
Extra: Extra: Using where
La columna sobre la que se aplican las condiciones es importante.
83. 3 - Optimización de consultas » EXPLAIN
EXPLAIN
SELECT City.Name, Country.Name
FROM City, Country
WHERE Country.Code = City.CountryCode
AND Country.Name="Spain"G
*********** 1. row ********** *********** 2. row **********
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: City table: Country
type: ALL type: eq_ref
possible_keys: NULL possible_keys: PRIMARY
key: NULL key: PRIMARY
key_len: NULL key_len: 3
ref: NULL ref: world.City.CountryCode
rows: 4079 rows: 1
Extra: Extra: Using where
La columna sobre la que se aplican las condiciones es importante.
84. 3 - Optimización de consultas » EXPLAIN
EXPLAIN
SELECT City.Name, Country.Name
FROM City, Country
WHERE Country.Code = City.CountryCode
AND Country.Code="ESP"G
*********** 1. row ********** *********** 2. row **********
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: Country table: City
type: const type: ALL
possible_keys: PRIMARY possible_keys: NULL
key: PRIMARY key: NULL
key_len: 3 key_len: NULL
ref: const ref: NULL
rows: 1 rows: 4079
Extra: Extra: Using where
La columna sobre la que se aplican las condiciones es importante.
85. 3 - Optimización de consultas » EXPLAIN
EXPLAIN
SELECT City.Name, Country.Name
FROM City, Country
WHERE Country.Code = City.CountryCode
AND Country.Code="ESP"G
*********** 1. row ********** *********** 2. row **********
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: Country table: City
type: const type: ALL
possible_keys: PRIMARY possible_keys: NULL
key: PRIMARY key: NULL
key_len: 3 key_len: NULL
ref: const ref: NULL
rows: 1 rows: 4079
Extra: Extra: Using where
La columna sobre la que se aplican las condiciones es importante.
86. 3 - Optimización de consultas » EXPLAIN
Forzar Índices
USE INDEX (índices)
IGNORE INDEX (índices)
FORCE INDEX (índices)
87. 3 - Optimización de consultas » EXPLAIN
STRAIGHT_JOIN
fuerza a que un JOIN se construya en el orden en el que se ha declarado
88. 3 - Optimización de consultas » EXPLAIN
ANALYZE TABLE
Actualiza las estadísticas de una tabla
Ejecutado periódicamente ayuda al optimizador
89. 3 - Optimización de consultas
3.4 - Metodología para elegir el
índice más óptimo
90. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
91. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
92. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
93. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
94. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
95. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
MySQL sólo utilizará un índice por tabla
96. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
MySQL sólo utilizará un índice por tabla
MySQL procesará un JOIN realizando el menor número de accesos
97. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
MySQL sólo utilizará un índice por tabla
MySQL procesará un JOIN realizando el menor número de accesos
empezando por la tabla con un índice más optimo
98. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
MySQL sólo utilizará un índice por tabla
MySQL procesará un JOIN realizando el menor número de accesos
empezando por la tabla con un índice más optimo
dictado por las condiciones WHERE
99. 3 - Optimización de consultas » Metodología
Metodología para elegir el índice más óptimo
Saber qué queremos hacer
Saber cuál es la manera más óptima
Saber qué hace mysql y por qué
MySQL sólo utilizará un índice por tabla
MySQL procesará un JOIN realizando el menor número de accesos
empezando por la tabla con un índice más optimo
dictado por las condiciones WHERE
y utilizando claves para seleccionar los registros de otras tablas
100. 3 - Optimización de consultas » Metodología
Ejemplo
EXPLAIN SELECT City.Name, Country.Name FROM City, Country WHERE
Country.Code = City.CountryCode AND Country.Code = "ESP";
101. 3 - Optimización de consultas » Metodología
I Formatear
EXPLAIN
SELECT City.Name,
Country.Name
FROM City,
Country
WHERE Country.Code = City.CountryCode
AND Country.Code = "ESP";
Existen Formateadores OnLine:
http://www.dpriver.com/pp/sqlformat.htm
102. 3 - Optimización de consultas » Metodología
II Dibujar Tablas y Relaciones
SELECT City.Name,
Country.Name
FROM City,
Country
WHERE Country.Code = City.CountryCode
AND Country.Code = "ESP";
103. 3 - Optimización de consultas » Metodología
II Dibujar Tablas y Relaciones
SELECT City.Name,
Country.Name
FROM City,
City Country
Country
WHERE Country.Code = City.CountryCode
AND Country.Code = "ESP";
104. 3 - Optimización de consultas » Metodología
II Dibujar Tablas y Relaciones
SELECT City.Name,
Country.Name
FROM City,
City Country
Country
WHERE Country.Code = City.CountryCode
AND Country.Code = "ESP";
105. 3 - Optimización de consultas » Metodología
II Dibujar Tablas y Relaciones
SELECT City.Name,
Country.Name
FROM City,
City Country
CountryCode
Country
WHERE Country.Code = City.CountryCode
Code
AND Country.Code = "ESP";
106. 3 - Optimización de consultas » Metodología
III Añadir columnas de SELECT y WHERE
SELECT City.Name,
Country.Name
FROM City,
City Country
CountryCode
Country
WHERE Country.Code = City.CountryCode
Code
AND Country.Code = "ESP";
107. 3 - Optimización de consultas » Metodología
III Añadir columnas de SELECT y WHERE
SELECT City.Name,
Country.Name
FROM City,
City Country
CountryCode
Country
Code = "ESP"
WHERE Country.Code = City.CountryCode
Code
AND Country.Code = "ESP";
108. 3 - Optimización de consultas » Metodología
III Añadir columnas de SELECT y WHERE
SELECT City.Name,
Country.Name
FROM City,
City Country
CountryCode
Country
Code = "ESP"
WHERE Country.Code = City.CountryCode
Code
AND Country.Code = "ESP";
Name Name
109. 3 - Optimización de consultas » Metodología
IV Añadir Índices
SELECT City.Name,
Country.Name
FROM City,
City Country
CountryCode
Country PK
Code = "ESP"
WHERE Country.Code = City.CountryCode PK
Code
AND Country.Code = "ESP";
Name Name
110. 3 - Optimización de consultas » Metodología
V Elegir el mejor plan de actuación
SELECT City.Name,
Country.Name City Country
FROM City, CountryCode
PK
Code = "ESP"
Country PK
Code
WHERE Country.Code = City.CountryCode
Name Name
AND Country.Code = "ESP";
111. 3 - Optimización de consultas » Metodología
V Elegir el mejor plan de actuación
Plan A
City » Country
Recorrer secuencialmente City
Por cada registro en City (4000):
Buscar una equivalencia en Country
usando PK
Seleccionar la fila sólo si Code = "ESP"
De las filas seleccionadas, leer:
City.Name (de la tabla)
Country.Name (de la tabla)
SELECT City.Name,
Country.Name City Country
FROM City, CountryCode
PK
Code = "ESP"
Country PK
Code
WHERE Country.Code = City.CountryCode
Name Name
AND Country.Code = "ESP";
112. 3 - Optimización de consultas » Metodología
V Elegir el mejor plan de actuación
Plan A Plan B
City » Country Country » City
Recorrer secuencialmente City Seleccionar Code = "ESP" de Country usando PK
Por cada registro en City (4000): Por cada registro en Country (1):
Buscar una equivalencia en Country Recorre secuencialmente City
usando PK Seleccionar la fila sólo si CountryCode = Code
Seleccionar la fila sólo si Code = "ESP" De las filas seleccionadas, leer:
De las filas seleccionadas, leer: City.Name (de la tabla)
City.Name (de la tabla) Country.Name (de la tabla)
Country.Name (de la tabla)
SELECT City.Name,
Country.Name City Country
FROM City, CountryCode
PK
Code = "ESP"
Country PK
Code
WHERE Country.Code = City.CountryCode
Name Name
AND Country.Code = "ESP";
113. 3 - Optimización de consultas » Metodología
V Elegir el mejor plan de actuación
Plan A Plan B
City » Country Country » City
Recorrer secuencialmente City Seleccionar Code = "ESP" de Country usando PK
Por cada registro en City (4000): Por cada registro en Country (1):
Buscar una equivalencia en Country Recorre secuencialmente City
usando PK Seleccionar la fila sólo si CountryCode = Code
Seleccionar la fila sólo si Code = "ESP" De las filas seleccionadas, leer:
De las filas seleccionadas, leer: City.Name (de la tabla)
City.Name (de la tabla) Country.Name (de la tabla)
Country.Name (de la tabla)
SELECT City.Name,
Country.Name City Country
FROM City, CountryCode
PK
Code = "ESP"
Country PK
Code
WHERE Country.Code = City.CountryCode
Name Name
AND Country.Code = "ESP";
114. 3 - Optimización de consultas » Metodología
V Elegir el mejor plan de actuación
Plan A Plan B
City » Country Country » City
Recorrer secuencialmente City Seleccionar Code = "ESP" de Country usando PK
Por cada registro en City (4000): Por cada registro en Country (1):
Buscar una equivalencia en Country Recorre secuencialmente City
usando PK Seleccionar la fila sólo si CountryCode = Code
Seleccionar la fila sólo si Code = "ESP" De las filas seleccionadas, leer:
De las filas seleccionadas, leer: City.Name (de la tabla)
City.Name (de la tabla) Country.Name (de la tabla)
Country.Name (de la tabla)
SELECT City.Name,
Country.Name City Country
FROM City, CountryCode
PK
Code = "ESP"
Country PK
Code
WHERE Country.Code = City.CountryCode
Name Name
AND Country.Code = "ESP";
115. 3 - Optimización de consultas » Metodología
V Cotejar con EXPLAIN
EXPLAIN
SELECT City.Name,
Country.Name
FROM City,
Country
WHERE Country.Code = City.CountryCode
AND Country.Code = "ESP";
*********** 1. row **********
table: Country
type: const
key: PRIMARY
rows: 1
Extra: City Country
*********** 2. row ********** CountryCode
PK
table: City Code = "ESP"
PK
type: ALL Code
key: NULL Name Name
rows: 4079
Extra: Using where
116. 3 - Optimización de consultas » Metodología
V Cotejar con EXPLAIN
EXPLAIN Plan B
SELECT City.Name, Country » City
Country.Name Seleccionar Code = "ESP" de Country usando PK
FROM City, Por cada registro en Country (1):
Country Recorre secuencialmente City
WHERE Country.Code = City.CountryCode Seleccionar la fila sólo si CountryCode = Code
AND Country.Code = "ESP"; De las filas seleccionadas, leer:
*********** 1. row ********** City.Name (de la tabla)
table: Country Country.Name (de la tabla)
type: const
key: PRIMARY
rows: 1
Extra: City Country
*********** 2. row ********** CountryCode
PK
table: City Code = "ESP"
PK
type: ALL Code
key: NULL Name Name
rows: 4079
Extra: Using where
117. 3 - Optimización de consultas » Metodología
VI Optimizar y Adaptar
¿Mi consulta es
todo lo óptima que podría?
Sí
Terminé de optimizar
No
Optimizar
¿Explain sigue mi
plan de ejecución?
Sí
No
Adaptar
118. 3 - Optimización de consultas » Metodología
VII Optimizar el uso de índices
SELECT City.Name, ¿Qué columnas añadir a un índice?
Country.Name
FROM City,
Columnas JOIN
Country
WHERE Country.Code = City.CountryCode En la 2ª tabla deben ser la 1ª columna de una clave
AND Country.Code = "ESP";
Condiciones WHERE
Country Se deben escribir sobre columnas indexadas, o
Crear un índice que contenga al resto de columnas
PK Code = "ESP"
Name
PK Code Columnas SELECT
Seleccionar sólo las necesarias
CountryCode
Si todas son parte del índice mejora el rendimiento
City
Name
Dividir la consulta en trozos más pequeños
Ayuda a saber qué parte tiene peor rendimiento
119. 3 - Optimización de consultas » Metodología
VII Optimizar el uso de índices
SELECT City.Name, ¿Qué columnas añadir a un índice?
Country.Name
FROM City,
Columnas JOIN
Country
WHERE Country.Code = City.CountryCode En la 2ª tabla deben ser la 1ª columna de una clave
AND Country.Code = "ESP";
Condiciones WHERE
Country Se deben escribir sobre columnas indexadas, o
Crear un índice que contenga al resto de columnas
PK Code = "ESP"
Name
PK Code Columnas SELECT
Seleccionar sólo las necesarias
CountryCode
Si todas son parte del índice mejora el rendimiento
City
Name
Dividir la consulta en trozos más pequeños
Ayuda a saber qué parte tiene peor rendimiento
120. 3 - Optimización de consultas » Metodología
VIII Adaptar
Para que MySQL siga nuestro plan:
Asegurarnos de que hemos creado los índices
ANALIZE TABLE
FORCE | IGNORE INDEX
Reescribir la consulta
WHERE
Condiciones JOIN
121. Ejercicio
SELECT SUM(salary)
FROM salaries
WHERE from_date BETWEEN '1999-01-01' AND '2000-01-01';
122. Ejercicio
SELECT SUM(salary)
FROM salaries
WHERE from_date BETWEEN '1999-01-01' AND '2000-01-01';
ALTER TABLE salaries ADD INDEX date_salary(from_date, salary);
123. Ejercicio
SELECT t.title,
AVG(s.salary) salario_medio
FROM titles t,
salaries s
WHERE t.emp_no = s.emp_no
AND t.to_date > NOW()
AND s.to_date > NOW()
GROUP BY t.title
ORDER BY salario_medio DESC;
124. Ejercicio
SELECT t.title,
AVG(s.salary) salario_medio
FROM titles t,
salaries s
WHERE t.emp_no = s.emp_no
AND t.to_date > NOW()
AND s.to_date > NOW()
GROUP BY t.title
ORDER BY salario_medio DESC;
ALTER TABLE titles ADD KEY curr_titles(to_date, emp_no, title);
125. Ejercicio
SELECT t.title,
AVG(s.salary) salario_medio
FROM titles t,
salaries s
WHERE t.emp_no = s.emp_no
AND t.to_date > NOW()
AND s.to_date > NOW()
GROUP BY t.title
ORDER BY salario_medio DESC;
ALTER TABLE titles ADD KEY to_date(to_date);
PRIMARY (emp_no, title, from_date)
126. Ejercicio
SELECT e.first_name,
e.last_name,
s.salary
FROM employees e,
titles t,
salaries s
WHERE e.emp_no = t.emp_no
AND e.emp_no = s.emp_no
AND t.title = 'Manager'
AND t.to_date > NOW()
AND s.to_date > NOW();
127. 3 - Optimización de consultas
3.5 - Optimización con Subconsultas
128. 3 - Optimización de consultas » Optimización con subconsultas
Consultas no correlativas
EXPLAIN
SELECT Name FROM City
WHERE City.ID IN (
SELECT Capital FROM Country WHERE Country.Continent = 'Europe'
)G
************* 1. row ************* ************** 2. row **************
id: 1 id: 2
select_type: PRIMARY select_type: DEPENDENT SUBQUERY
table: City table: Country
type: ALL type: ALL
possible_keys: NULL possible_keys: NULL
key: NULL key: NULL
key_len: NULL key_len: NULL
ref: NULL ref: NULL
rows: 4079 rows: 239
Extra: Using where Extra: Using where
Las subconsultas no correlativas son aquellas que se pueden ejecutar de
manera independiente a la consulta principal.
129. 3 - Optimización de consultas » Optimización con subconsultas
Consultas no correlativas
EXPLAIN
SELECT Name FROM City, (
SELECT Capital FROM Country WHERE Country.Continent = 'Europe'
) co
WHERE City.ID = co.CapitalG
******* 1. row ******* ******* 2. row ******* ******* 3. row *******
id: 1 id: 1 id: 2
select_type: PRIMARY select_type: PRIMARY select_type: DERIVED
table: <derived2> table: City table: Country
type: ALL type: eq_ref type: ALL
possible_keys: NULL possible_keys: PRIMARY possible_keys: NULL
key: NULL key: PRIMARY key: NULL
key_len: NULL key_len: 4 key_len: NULL
ref: NULL ref: co.Capital ref: NULL
rows: 46 rows: 1 rows: 239
Extra: Extra: ...
Las subconsultas no correlativas se pueden situar como una tabla con la
que hacer JOIN
130. 3 - Optimización de consultas » Optimización con subconsultas
Consultas no correlativas
EXPLAIN
SELECT Name
FROM City, Country
WHERE City.ID = Country.Capital
AND Country.Continent = 'Europe'G
************* 1. row ************* ************** 2. row **************
id: 1 id: 1
select_type: SIMPLE select_type: SIMPLE
table: Country table: City
type: ALL type: eq_ref
possible_keys: NULL possible_keys: PRIMARY
key: NULL key: PRIMARY
key_len: NULL key_len: 4
ref: NULL ref: world.Country.Capital
rows: 239 rows: 1
Extra: Using where Extra:
A veces se pueden reescribir como un JOIN
131. 3 - Optimización de consultas » Optimización con subconsultas
Funciones de agregación
SELECT Name, Population
FROM Country,
(SELECT MAX(Population) max_pop FROM Country) co
WHERE Country.Population = co.max_pop;
Y otras, como cuando se usan funciones de agregación, no.
132. 3 - Optimización de consultas » Optimización con subconsultas
Condiciones OR
SELECT ci.Name
FROM City ci, Country co, CountryLanguage cl
WHERE ci.CountryCode = co.Code
AND co.Code = cl.CountryCode
AND (ci.Name LIKE 'Es%' OR cl.Language LIKE 'Es%');
Las condiciones OR sobre campos de varias tablas no permite que se
puedan usar índices.
133. 3 - Optimización de consultas » Optimización con subconsultas
Condiciones OR
ALTER TABLE City ADD INDEX (CountryCode), ADD INDEX (Name);
ALTER TABLE CountryLanguage ADD INDEX (Language);
SELECT ci.Name
FROM City ci,
( SELECT ID FROM City ci, Country co, CountryLanguage cl
WHERE ci.CountryCode = co.Code
AND co.Code = cl.CountryCode
AND cl.Language LIKE 'Es%'
UNION
SELECT ID FROM City ci
WHERE ci.Name LIKE 'Es%'
) ci_ids
WHERE ci.ID = ci_ids.ID;
Se puede reescribir como subconsultas para ayudar a MySQL.
135. 3 - Optimización de consultas » Optimización usando cachés propias
Cachés propias
City Country
Name Continent
Name
Si vamos a consultar muchas veces las ciudades por continente, nos
puede interesar desnormalizar creando una tabla caché que relacione
directamente las ciudades con sus continentes.
136. 3 - Optimización de consultas » Optimización usando cachés propias
Cachés propias
City Country City_Country
City_Name
Name Continent Continent
Name Country_Name
Si vamos a consultar muchas veces las ciudades por continente, nos
puede interesar desnormalizar creando una tabla caché que relacione
directamente las ciudades con sus continentes.
137. 3 - Optimización de consultas » Optimización usando cachés propias
Cachés propias
City Country City_Country
City_Name
Name Continent Continent
Name Country_Name
?
Si vamos a consultar muchas veces las ciudades por continente, nos
puede interesar desnormalizar creando una tabla caché que relacione
directamente las ciudades con sus continentes.
141. 3 - Optimización de consultas » MySQL 5.5
MySQL 5.5
Actualizar es un cambio "fácil" de llevar a cabo.
142. 3 - Optimización de consultas
3.7 - Optimización con MySQL 5.5
3.7.1 - Particionado
143. 3 - Optimización de consultas » Particionado
Particionado
http://www.slideshare.net/datacharmer/mysql-partitions
144. 3 - Optimización de consultas
3.7 - Optimización con MySQL 5.5
3.7.2 - Triggers
145. 3 - Optimización de consultas » Triggers
Triggers
Código que se ejecuta:
ANTES
DESPUÉS
de
INSERTAR
MODIFICAR
BORRAR
146. 3 - Optimización de consultas » Triggers
Triggers
Hasta 6 triggers por tabla
Sintaxis:
CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
CREATE TRIGGER ins_sum BEFORE INSERT ON account
FOR EACH ROW SET @sum = @sum + NEW.amount;
148. 3 - Optimización de consultas » Triggers
Coste
A: 15,16 1 Índice
B: 15,20 1 Índice + 1 Trigger
C: 14,87 1 Trigger
15,2
11,4
7,6
3,8
0
A B C
Un trigger apenas afecta al rendimiento en comparación a un índice.
149. 1- Introducción. ¿Por qué optimizar?
2- Arquitectura de MySQL
3- Optimización de consultas
4.- Ruegos y Preguntas
151. Optimización del rendimiento con MySQL ( LSWC Noviembre 2011)
Víctor Jiménez Cerrada <vjimenez@warp.es>
@capitangolo
http://slideshare.net/capitangolo