Estamos executando um site (Moodle) que os usuários atualmente acham lento. Acho que rastreei o problema do MySQL criando tabelas temporárias no disco. Eu observo a variável created_tmp_disk_tables
na administração do servidor Mysql Workbench e o número aumenta com aproximadamente 50 tabelas/s. Após um dia de uso, created_tmp_disk_tables
é >100k. Além disso, a memória não parece ser liberada. O uso continua aumentando até que o sistema se torne praticamente inutilizável e tenhamos que reiniciar o MySQL. Eu preciso reiniciá-lo quase todos os dias e ele começa usando cerca de 30-35% da memória disponível e terminando o dia com 80%.
Eu não tenho blobs no banco de dados e também não tenho controle sobre as consultas, então não posso tentar otimizá-las. Também usei o Percona Configuration Wizard para gerar um arquivo de configuração, mas o my.ini também não resolveu meu problema.
Perguntas
O que devo mudar para impedir o MySQL de criar tabelas temporárias no disco? Existem configurações que eu preciso alterar? Devo jogar mais memória nele?
Como posso impedir o MySQL de consumir minha memória?
Editar
Ativei slow_queries
o log e descobri que a consulta SELECT GET_LOCK()
foi registrada como lenta. Uma pesquisa rápida revelou que eu havia permitido conexões persistentes na configuração do PHP ( mysqli.allow_persistent = ON
). Eu desliguei isso. Isso reduziu a taxa na qual o MySQL consome memória. Ele ainda está criando tabelas temporárias.
Eu também verifiquei se o key_buffer size
é grande o suficiente. Eu olhei para a variável key_writes
. Isso deve ser zero. Se não, aumente o key_buffer_size
.Eu tenho zero key_reads
e zero key_writes
, então suponho que o key_buffer_size
é grande o suficiente.
Aumentei o tmp_table_size
e max-heap-table-size
para 1024M pois um aumento em created_tmp_disk_tables pode indicar que as tabelas não cabem na memória. Isso não resolveu.
Editar 2
Se você vir muitos sort_merge_passes
por segundo na saída SHOW GLOBAL STATUS, considere aumentar o sort_buffer_size
valor. Eu tinha 2 sort_merge_passes
em uma hora, então considero sort_buffer_size
que é grande o suficiente.
Ref: Manual do MySQL emsort_buffer_size
Editar 3
Modifiquei os buffers de classificação e junção, conforme sugerido por @RolandoMySQLDBA. O resultado é exibido na tabela abaixo, mas acho que created_tmp_tables_on_disk
ainda é alto. Reiniciei o servidor mysql depois de alterar o valor e verifiquei created_tmp_tables_on_disk
depois de um dia (8h) e calculei a média. Alguma outra sugestão? Parece-me que há algo que não cabe dentro de algum tipo de recipiente, mas não consigo descobrir o que é.
+---------------------+-------------+-------------+--------------------+
| 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 é a minha configuração:
+-----------------------+-----------------------+
|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 |
+-----------------------+-----------------------+
Informação 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 configuração foi dada a mim, então eu tenho controle limitado sobre ela. O servidor da web está usando muito pouca CPU e RAM, então excluí essa máquina como um gargalo. A maioria das configurações do MySQL se origina de uma ferramenta de geração automática de configuração.
Eu monitorei o sistema usando PerfMon durante alguns dias representativos. A partir disso, concluo que não é o sistema operacional que está trocando para o 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
Olhando para o
my.ini
, tenho duas sugestõesSUGESTÃO #1
Eu aumentaria as seguintes configurações no seu
my.ini
Isso fará com que algumas junções e ordenações permaneçam na memória. É claro que, uma vez que a
JOIN
ou anORDER BY
precise de mais de4M
, ele será paginado para o disco como uma tabela MyISAM.Se você não puder fazer login como
root@localhost
, reinicie o mysql comSe você puder fazer login como root@localhost, não precisará reiniciar o mysql para usar essas configurações.
Basta executar isso no cliente MySQL:
SUGESTÃO #2
Como seus dados estão na unidade
D:
, você pode ter E/S de disco na unidadeC:
.Execute esta consulta:
Como executo o mysql na minha área de trabalho com padrões, minhas tabelas temporárias estão sendo gravadas no Drive
C:
. Se a unidade D for um disco melhor que a unidadeC:
, talvez você possa mapear tabelas temporárias para a unidadeD:
configurando tmpdir damy.ini
seguinte maneira:Você terá que reiniciar o mysql já que tmpdir não é uma variável dinâmica.
De uma chance !!!
ATUALIZAÇÃO 2013-11-29 10:09 EST
SUGESTÃO #3
Dado o fato de que o MySQL está rodando no Windows e você não pode tocar nas consultas no pacote principal, tenho duas idéias que devem ser feitas juntas.
IDEIA #1: Mova o banco de dados para uma máquina Linux
Você deve ser capaz de
IDEIA #2: Reconfigure o Moodle para apontar para a máquina Linux
O Moodle foi projetado para LAMP em primeiro lugar. Basta alterar os arquivos de configuração para apontar para a máquina Linux em vez de localhost.
Aqui está um link para um documento antigo do Moodle 2.3 sobre como configurar o MySQL: http://docs.moodle.org/23/en/Installing_Moodle#Create_an_empty_database
Tenho certeza de que os documentos mais recentes também estão disponíveis.
Qual é o ponto de mover o banco de dados para Linux ???
Como isso ajuda a situação da tabela temporária ???
Eu sugeriria então configurar um disco RAM como a pasta de destino para suas tabelas temporárias
Jan 04, 2013
: Existe um mecanismo ou truque do MySQL para evitar gravar tantas tabelas temporárias no disco?Dec 17, 2012
: Por que o MySQL produz tantos arquivos MYD temporários? (Instruções reais)Nov 30, 2012
: É ruim criar muitas tabelas temporárias do mysql simultaneamente?A criação da tabela temporária ainda acontecerá, mas será gravada na RAM e não no disco. reduzindo a E/S de disco.
ATUALIZAÇÃO 2013-11-29 11:24 EST
SUGESTÃO #4
Eu sugiro revisitar a SUGESTÃO #2 com um disco RAID-0 rápido (32+ GB), configurando-o como Drive T: (T para Temp). Depois de instalar esse disco, adicione isso a
my.ini
:A reinicialização do MySQL seria necessária, usando
BTW eu disse RAID-0 de propósito para que você possa obter um bom desempenho de gravação em um RAID-1, RAID-10. Um disco de tabela tmp não é algo que eu tornaria redundante.
Sem otimizar as consultas como @RaymondNijland comenta, você não pode reduzir a contagem de criação de tabelas temporárias de forma alguma.
SUGGESTION #3
eSUGGESTION #4
oferecer a aceleração da criação de tabelas temporárias e E/S de tabelas temporárias como a única alternativa.Eu respondo minha própria pergunta aqui para completar
Vou selecionar @RolandoMySQLDBA como a resposta preferida porque me deu mais dicas, embora não tenha realmente resolvido meu problema.
Abaixo estão os resultados da minha investigação
Conclusão
O MySQL no Windows apenas cria muitas tabelas temporárias e o ajuste do MySQL modificando o conteúdo dos arquivos de configuração não ajudou.
Detalhes
A tabela detalha os parâmetros que modifiquei em my.ini respectivamente antes de executar qualquer consulta. O MySQL foi reiniciado entre cada teste.
Usei como template o my.ini encontrado na pergunta original e então alterei o valor dos parâmetros um a um conforme a tabela abaixo.
Eu usei o JMeter para gerar 100 solicitações da Web simultâneas (já que isso representava nosso uso) repetidas 10 dez vezes. Cada um
Test
consistia, assim, em 1000 pedidos no total. Isso resultou em chamadas de banco de dados subsequentes. Isso mostrou que o MySQL criaria muitas tabelas temporárias, independentemente de quais parâmetros de configuração alteramos.*Média de três corridas
As imagens abaixo descrevem a quantidade de memória e CPU necessária ao servidor de banco de dados para as diferentes configurações. As linhas pretas indicam os valores mínimo e máximo e as barras azuis indicam os valores inicial e final. A memória máxima foi
4096M
a indicada na questão.You should also check whether your In-Memory Temporary Table Size is limited by Maximum Heap Table Size variable.
When using the MEMORY storage engine for in-memory temporary tables, MySQL automatically converts an in-memory temporary table to an on-disk table if it becomes too large.
If the space required to build a temporary table exceeds either
tmp_table_size
ormax_heap_table_size
, MySQL creates a disk-based table in the server'stmpdir
directory. The maximum size for in-memory temporary tables is defined by thetmp_table_size
ormax_heap_table_size
value, whichever is smaller.