MySQL crea tablas temporales en el disco. ¿Como lo detengo?


27

Estamos ejecutando un sitio (Moodle) que los usuarios actualmente encuentran lento. Creo que he rastreado el problema hasta MySQL creando tablas temporales en el disco. Miro la variable created_tmp_disk_tablesen la administración del servidor Mysql Workbench y el número aumenta con aproximadamente 50 tablas / s. Después de un día de uso, created_tmp_disk_tableses> 100k. Además, la memoria no parece ser liberada. El uso sigue aumentando hasta que el sistema se vuelve prácticamente inutilizable y tenemos que reiniciar MySQL. Necesito reiniciarlo casi todos los días y comienza con el uso de aproximadamente el 30-35% de la memoria disponible y termina el día con el 80%.

No tengo blobs en la base de datos y tampoco control sobre las consultas, así que no puedo intentar optimizarlas. También he usado el Asistente de confirmación de Percona para generar un archivo de configuración, pero my.ini tampoco resolvió mi problema.

Preguntas

  1. ¿Qué debo cambiar para evitar que MySQL cree tablas temporales en el disco? ¿Hay configuraciones que necesito cambiar? ¿Debería arrojarle más memoria?

  2. ¿Cómo puedo evitar que MySQL me coma la memoria?

Editar

Habilité el slow_queriesregistro y descubrí que la consulta SELECT GET_LOCK()se registró como lenta. Una búsqueda rápida reveló que había permitido conexiones persistentes en la configuración de PHP ( mysqli.allow_persistent = ON). Apagué esto. Esto redujo la velocidad a la que MySQL consume memoria, aunque todavía está creando tablas temporales.

También verifiqué que key_buffer sizees lo suficientemente grande. Miré la variable key_writes. Esto debería ser cero. Si no, aumente key_buffer_size. Tengo cero key_readsy cero, key_writesasí que supongo que key_buffer_sizees lo suficientemente grande.

Aumenté el tmp_table_sizey max-heap-table-sizeal 1024M como un aumento en Created_tmp_disk_tables puede indicar que las tablas no pueden caber en la memoria. Esto no lo resolvió.

Ref: http://www.mysqlperformanceblog.com/2007/08/16/how-much-overhead-is-caused-by-on-disk-temporary-tables/

Editar 2

Si ve muchos sort_merge_passespor segundo en la salida SHOW GLOBAL STATUS, puede considerar aumentar el sort_buffer_sizevalor. Tenía 2 sort_merge_passesen una hora, así que considero sort_buffer_sizeque es lo suficientemente grande.

Ref: Mysql Manual sobre sort_buffer_size

Editar 3

He modificado la ordenación y unir buffers como lo sugiere @RolandoMySQLDBA. El resultado se muestra en la tabla a continuación, pero creo que created_tmp_tables_on_disktodavía es alto. Reinicié el servidor mysql después de cambiar el valor y verifiqué created_tmp_tables_on_diskdespués de un día (8h) y calculé el promedio. ¿Cualquier otra sugerencia? Me parece que hay algo que no cabe dentro de algún tipo de contenedor, pero no puedo entender qué es.

+---------------------+-------------+-------------+--------------------+
| Tmp_table_size,     | Sort_buffer | Join_buffer | No of created      |
| max_heap_table_size |             |             | tmp_tables on disk |
+---------------------+-------------+-------------+--------------------+
| 125M                | 256K        | 256K        |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 512K        | 512K        |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 1M          | 1M          |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 4M          | 4M          |  100k/h            |
+---------------------+-------------+-------------+--------------------+   



Esta es mi configuración:

+-----------------------+-----------------------+
|DATABASE SERVER        |WEB SERVER             |
+-----------------------+-----------------------+
|Windows Server 2008 R2 |Windows Server 2008 R2 |
+-----------------------+-----------------------+
|MySQL 5.1.48           |IIS 7.5                |
+-----------------------+-----------------------+
|4 Core CPU             |4 Core CPU             |
+-----------------------+-----------------------+
|4GB RAM                |8GB RAM                |
+-----------------------+-----------------------+

Información Adicional

+--------------------+---------+
|PARAM               |VALUE    |
+--------------------+---------+
|Num of tables in Db |361      |
+--------------------+---------+
|Size of database    |2.5G     |
+--------------------+---------+
|Database engine     |InnoDB   |
+--------------------+---------+
|Read/write ratio    |3.5      |
|(Innodb_data_read/  |         |
|innodb_data_written)|         |
+--------------------+---------+
|Avg table size      |15k rows |
+--------------------+---------+
|Max table size      |744k rows|
+--------------------+---------+

Esta configuración me fue dada, así que tengo un control limitado sobre ella. El servidor web está usando muy poca CPU y RAM, así que he excluido esa máquina como un cuello de botella. La mayoría de la configuración de MySQL se origina en una herramienta de generación automática de configuración.

He monitoreado el sistema usando PerfMon durante algunos días representativos. A partir de eso, llego a la conclusión de que no es el sistema operativo el que está cambiando al disco.

My.ini

[client]
port=3306
[mysql]
default-character-set=utf8

[mysqld]
port=3306
basedir="C:/Program Files/MySQL/MySQL Server 5.1/"
datadir="D:/DBs/Data/"
default-character-set=utf8
default-storage-engine=INNODB
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
max_connections=125
query_cache_size=350M
table_cache=1520
tmp_table_size=125M
table-definition-cache= 1024
max-heap-table-size= 32M
thread_cache_size=38

MyISAM Specific options
myisam_max_sort_file_size=100G
myisam_sort_buffer_size=125M
key_buffer_size=55M
read_buffer_size=1024K
read_rnd_buffer_size=256K
sort_buffer_size=1024K
join_buffer_size=1024K


INNODB Specific options
innodb_data_home_dir="D:/DBs/"
innodb_additional_mem_pool_size=32M
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=16M
innodb_buffer_pool_size=2G
innodb_log_file_size=407M
innodb_thread_concurrency=8

Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Paul White dice GoFundMonica

Respuestas:


16

Mirando el my.ini, tengo dos sugerencias

SUGERENCIA # 1

Me gustaría subir la siguiente configuración en su my.ini

sort_buffer_size=4M
join_buffer_size=4M

Esto hará que algunas uniones y clasificaciones permanezcan en la memoria. Por supuesto, una vez que a JOINo a ORDER BYnecesite más que 4M, se paginará en el disco como una tabla MyISAM.

Si no puede iniciar sesión como root@localhost, reinicie mysql con

C:\> net stop mysql
C:\> net start mysql

Si puede iniciar sesión como root @ localhost, no tiene que reiniciar mysql para usar esta configuración.

Simplemente ejecute esto en el cliente MySQL:

SET @FourMegs = 1024 * 1024 * 4;
SET GLOBAL sort_buffer_size = @FourMegs;
SET GLOBAL join_buffer_size = @FourMegs;

SUGERENCIA # 2

Como sus datos están en la unidad D:, es posible que tenga E / S de disco en la unidad C:.

Por favor ejecute esta consulta:

mysql> show variables like 'tmpdir';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tmpdir        | C:\Windows\TEMP |
+---------------+-----------------+
1 row in set (0.00 sec)

Como ejecuto mysql en mi escritorio con los valores predeterminados, mis tablas temporales se escriben en Drive C:. Si Drive D es un mejor disco que Drive C:, quizás pueda asignar tablas temporales a Drive D:configurando tmpdir de la my.inisiguiente manera:

tmpdir="D:/DBs/"

Deberá reiniciar mysql ya que tmpdir no es una variable dinámica.

Darle una oportunidad !!!

ACTUALIZACIÓN 2013-11-29 10:09 EST

SUGERENCIA # 3

Dado el hecho de que MySQL se está ejecutando en Windows y no puede tocar las consultas en el paquete principal, tengo dos ideas que deben hacerse juntas.

IDEA # 1: mover la base de datos a una máquina Linux

Deberias ser capaz de

  • Configurar una máquina Linux
  • Instale MySQL en la máquina Linux
  • Habilite el registro binario para MySQL en Windows
  • mysqldump la base de datos a un archivo de texto SQL
  • Cargue el archivo SQL en MySQL que se ejecuta en Linux
  • Configurar la replicación de MySQL / Windows a MySQL / Linux

IDEA # 2: reconfigurar Moodle para que apunte a la máquina Linux

Moodle fue diseñado para LAMP en primer lugar. Simplemente cambie los archivos de configuración para apuntar a la máquina Linux en lugar de localhost.

Aquí hay un enlace a un antiguo documento de Moodle 2.3 sobre la configuración de MySQL: http://docs.moodle.org/23/en/Installing_Moodle#Create_an_empty_database

Estoy seguro de que los últimos documentos también están disponibles.

¿Cuál es el punto de mover la base de datos a Linux?

¿Cómo ayuda esto a la situación de la tabla temporal?

Entonces sugeriría configurar un disco RAM como la carpeta de destino para sus tablas temporales

La creación de la tabla temporal seguirá sucediendo, pero se escribirá en la RAM en lugar de en el disco. Reducción de E / S de disco.

ACTUALIZACIÓN 2013-11-29 11:24 EST

SUGERENCIA # 4

Sugeriría volver a visitar la SUGERENCIA # 2 con un disco RAID-0 rápido (32+ GB), configurándolo como Unidad T: (T para Temp). Después de instalar dicho disco, agregue esto a my.ini:

[mysqld]
tmpdir="T:\"

Se requeriría reiniciar MySQL, usando

net stop mysql
net start mysql

Por cierto, dije RAID-0 a propósito para que pueda obtener un buen rendimiento de escritura sobre un RAID-1, RAID-10. Un disco de tabla tmp no es algo que haría redundante.

Sin optimizar las consultas como ha estado comentando @RaymondNijland, no puede reducir el recuento de creación de la tabla temporal de ninguna manera. SUGGESTION #3y SUGGESTION #4ofrecen acelerar la creación de la tabla temporal y la E / S de la tabla temporal como la única alternativa.


13

Respondo mi propia pregunta aquí para completar

Seleccionaré @RolandoMySQLDBA como la respuesta preferida porque me dio la mayor cantidad de pistas aunque en realidad no resolvió mi problema.

A continuación se muestran los resultados de mi investigación.

Conclusión

MySQL en Windows solo crea muchas tablas temporales y ajustar MySQL modificando el contenido de los archivos de configuración no ayudó.

Detalles

La tabla detalla los parámetros que he modificado en my.ini respectivamente antes de ejecutar cualquier consulta. MySQL se reinició entre cada prueba.

Usé el my.ini que se encuentra en la pregunta original como plantilla y luego cambié el valor de los parámetros uno por uno de acuerdo con la tabla a continuación.

Solía JMeter para generar 100 peticiones web concurrentes (como el representado nuestro uso) se repiten de 10 diez veces. Cada uno Testconstaba de 1000 solicitudes en total. Esto dio lugar a posteriores llamadas a la base de datos. Esto demostró que MySQL crearía muchas tablas temporales independientemente de los parámetros de configuración que cambiémos.

+----+------------+-------+---------------+------------+
|Test|Parameter   |Value  |NumOfTempTables|Db Max Conn |
+----+------------+-------+---------------+------------+
| 1  |key_buffer_ | 25M   | 30682         | 29         |
|    |size        |       |               |            | 
+----+------------+-------+---------------+------------+
| 2  |key_buffer_ | 55M   | 30793         | 29         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 3  |key_buffer_ | 100M  | 30666         | 28         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 4  |key_buffer_ | 125M  | 30593         | 24         |
|    |size        |       |               |            | 
+----+------------+-------+---------------+------------+
| 5  |query_cache_| 100M  | 30627         | 32         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 6  |query_cache_| 250M  | 30761         | 26         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 7  |query_cache_| 500M  | 30864         | 83*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 8  |query_cache_| 1G    | 30706         | 75*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 9  |tmp_table_  | 125M  | 30724         | 31         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 10 |tmp_table_  | 250M  | 30689         | 90*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 11 |tmp_table_  | 500M  | 30792         | 28         |
|    |size        |       |               |            |  
+----+------------+-------+---------------+------------+
| 12 |Sort_buffer&| 256K  | 30754         | 28         |
|    |Join_buffer |       |               |            |
+----+------------+-------+---------------+------------+
| 13 |Sort_buffer&| 512K  | 30788         | 30         |
|    |Join_buffer |       |               |            | 
+----+------------+-------+---------------+------------+
| 14 |Sort_buffer&| 1M    | 30788         | 28         |
|    |Join_buffer |       |               |            | 
+----+------------+-------+---------------+------------+
| 15 |Sort_buffer&| 4M    | 30642         | 35         |
|    |Join_buffer |       |               |            |
+----+------------+-------+---------------+------------+
| 16 |innodb-     | 1G    | 30695         | 33         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            |
+----+------------+-------+---------------+------------+
| 17 |innodb-     | 2G    | 30791         | 28         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            | 
+----+------------+-------+---------------+------------+
| 18 |innodb-     | 3G    | 30719         | 34         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            |  
+----+------------+-------+---------------+------------+

* Promedio de tres carreras

Las siguientes imágenes muestran la cantidad de memoria y CPU que el servidor de base de datos requiere para las diferentes configuraciones. Las líneas negras indican los valores mínimos y máximos y las barras azules indican los valores inicial y final. La memoria máxima fue la 4096Mindicada en la pregunta.

Uso de memoria Uso de CPU


¿Qué motor de almacenamiento está utilizando? ¿MyiSAM? Si no está utilizando tablas MyISAM, no tiene sentido confiar en key_buffer_size. si está utilizando el motor de almacenamiento innodb, cuál es el tamaño de innodb_buffer_pool_size. ¿Estás usando query_cache?
kasi
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.