Por que o MySQL diz que estou com falta de memória?

9

Eu estava tentando executar um bastante grande INSERT...SELECTno MySQL com JDBC, e recebi a seguinte exceção:

Exception in thread "main" java.sql.SQLException: Out of memory (Needed 1073741824 bytes)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)

Como na verdade não estou retornando um objeto ResultSet, achei que o espaço de heap Java não deveria ser um problema. No entanto, tentei fazê-lo de qualquer maneira e não adiantou. Tentei então executar a instrução no MySQL Workbench e obtive essencialmente a mesma coisa:

Error Code 5: Out of memory (Needed 1073741816 bytes)

Eu deveria ter bastante RAM para concluir essas operações (o suficiente para caber em toda a tabela da qual estou selecionando), mas acho que existem várias configurações que preciso ajustar para aproveitar toda a minha memória. Estou executando uma Instância extra grande dupla do Amazon EC2 com memória alta com uma AMI do Windows Server 2008. Tentei mexer no arquivo my.ini para usar configurações melhores, mas, pelo que sei, posso ter piorado as coisas. Aqui está um despejo desse arquivo:

[client]
port=3306
[mysql]
default-character-set=latin1
[mysqld]
port=3306
basedir="C:/Program Files/MySQL/MySQL Server 5.5/"
datadir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/"
character-set-server=latin1
default-storage-engine=INNODB
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
max_connections=100
query_cache_size=1024M
table_cache=256
tmp_table_size=25G
thread_cache_size=8
myisam_max_sort_file_size=100G
myisam_repair_threads = 2
myisam_sort_buffer_size=10G
key_buffer_size=5000M
bulk_insert_buffer_size = 4000M
read_buffer_size=8000M
read_rnd_buffer_size=8000M
sort_buffer_size=1G
innodb_additional_mem_pool_size=26M
innodb_flush_log_at_trx_commit=2
innodb_log_buffer_size=13M
innodb_buffer_pool_size=23G
innodb_log_file_size=622M
innodb_thread_concurrency=18
innodb_file_per_table=TRUE
join_buffer_size=4G
max_heap_table_size = 10G

Portanto, é apenas uma questão de alterar as configurações acima para funcionar melhor no meu ambiente? Se sim, quais configurações devo usar? Eu sou o único que usa essa instância; Eu o uso no meu projeto de hobby pessoal, que envolve análise estatística de grandes conjuntos de dados. Como tal, estou livre para consumir todos os recursos disponíveis para minhas próprias consultas.

Se não se trata de alterar essas configurações, qual é o problema? Obrigado por qualquer ajuda que você possa oferecer para configurar melhor tudo.

Michael McGowan
fonte
Qualquer pessoa que use cache de consulta 1g não tem idéia do que está fazendo.
@winmutt Você pode muito bem estar correto, mas seu comentário não ajuda ninguém sem maiores explicações. Você poderia nos ajudar, dando razões para o seu sentimento?
Michael McGowan
Uma ferramenta útil para começar é tools.percona.com/wizard
KCD

Respostas:

9

Como essa é uma instalação do Windows, o @DTest ainda fornece a direção correta inicial.

Aplique a seguinte fórmula:

A maioria das pessoas usa isso:

Maximum MySQL Memory Usage = innodb_buffer_pool_size + key_buffer_size + (read_buffer_size + sort_buffer_size) X max_connections

Eu prefiro isso:

Maximum MySQL Memory Usage = innodb_buffer_pool_size + key_buffer_size + ((read_buffer_size + read_rnd_buffer_size + sort_buffer_size + join_buffer_size) X max_connections)

Essas variáveis ​​são as que você precisa ajustar até que a fórmula gere 80% da RAM instalada ou menos.

sort_buffer_size
read_buffer_size
read_rnd_buffer_size
join_buffer_size
max_connections
RolandoMySQLDBA
fonte
4

Eu tentaria diminuir o tamanho do buffer. Torná-los tão grandes quanto você os terá causará problemas. Quanta memória você tem disponível para executar estes valores:

query_cache_size=1024M
myisam_max_sort_file_size=100G
myisam_sort_buffer_size=10G
key_buffer_size=5000M
bulk_insert_buffer_size = 4000M
read_buffer_size=8000M
read_rnd_buffer_size=8000M
sort_buffer_size=1G
innodb_buffer_pool_size=23G

Alguns dos tamanhos de buffer são alocados por thread, por exemplo myisam_sort_buffer_size de 10G aloca 10G para cada thread.

Primeiro, eu reduzia drasticamente esses valores e depois investigava quais valores você realmente precisa para ter tanta RAM alocada (se houver).

Derek Downey
fonte
4

Uma maneira rápida de determinar quanta memória o MySQL pensa que poderia alocar é a seguinte:

wget mysqltuner.pl

perl mysqltuner.pl

Quando você executa esse script, ele informa qual a porcentagem da RAM instalada que o MySQL acha que pode alocar com segurança. Se a resposta for superior a 100%, você definitivamente precisará diminuir o tamanho do buffer. O principal deles é o seguinte:

sort_buffer_size
read_buffer_size
record_rnd_buffer_size
join_buffer_size
max_connections
key_buffer_size (não é realmente eficaz passado 4G)

O @DTest já definiu a direção para você na resposta dele, então +1 para a resposta dele. O script perl dirá o que acontece se você não o definir ou se alterar algum valor. Aqui está um exemplo:

Um cliente meu tem
read_buffer_size = 128K
read_rnd_buffer_size = 256K
sort_buffer_size = 2M
join_buffer_size = 128K
max_connections = 1050

Aqui está a saída do mysqltuner.pl:

MySQLTuner 1.2.0 - Principais
relatórios de erros do Hayden , solicitações de recursos e downloads em http://mysqltuner.com/
Execute com '--help' para obter opções adicionais e filtragem de saída.
Por favor, digite seu login administrativo do MySQL: lwdba
Por favor, digite seu MySQL administrativo senha:

-------- Estatísticas Gerais ---------------------------------------- ----------
[-] Verificação de versão ignorada para o script MySQLTuner
[OK] Atualmente executando o MySQL com suporte 5.0.51a-community-log
[!!] Alternar para o SO de 64 bits - O MySQL não pode usar no momento toda a sua RAM

-------- Estatísticas do mecanismo de armazenamento --------------------------------------- ----
[-] Status: + Archive -BDB + Federado + InnoDB -ISAM -NDBCluster
[-] Dados nas tabelas MyISAM: 319M (Tabelas: 108)
[-] Dados nas tabelas InnoDB: 2M (Tabelas: 5)
[!!] Total de tabelas fragmentadas: 22

-------- Métricas de desempenho ---------------------------------------- ---------
[-] Compatível com: 52d 23h 15m 57s (72M q [15.875 qps], conexão 241K, TX: 2B, RX: 1B)
[-] Lê / grava: 59% / 41%
[-] Total de buffers: 34,0M globais + 2,7M por thread (1050 max threads)
[!!] Alocar> 2 GB de RAM em sistemas de 32 bits pode causar instabilidade no sistema
[!!] Máximo possível de uso de memória: 2,8 G (72% da RAM instalada)
[OK] Consultas lentas: 0% (54 / 72M)
[OK] Maior uso de conexões disponíveis: 6% (65/1050)
[OK] Tamanho do buffer da chave / índices MyISAM totais: 8.0M / 82,1M
[OK] Taxa de acertos do buffer de teclas: 100,0% (4B em cache / 1M lê)
[!!] O cache de consulta está desabilitado
[OK] Classificações que requerem tabelas temporárias: 0% (0 classificações de temperatura / classificações de 948K)
[OK] Tabelas temporárias criadas no disco: 3% (11K no disco / 380K total)
[!!] O cache do encadeamento está desabilitado
[!!] Taxa de acertos no cache da tabela: 0% (64 aberto / 32K aberto)
[OK] Abrir arquivo limite usado: 2% (125 / 5K)
[OK] Bloqueios de tabela adquiridos imediatamente: 99% (30M imediatos / 30M bloqueios)
[OK] Tamanho de dados InnoDB / buffer pool: 2.7M / 8.0M

-------- Recomendações ----------------------------------------- ------------
Recomendações gerais:
Execute OPTIMIZE TABLE para desfragmentar tabelas para obter melhor desempenho
Habilite o log de consultas lento para solucionar problemas de consultas incorretas
Defina thread_cache_size como 4 como valor inicial
Aumente table_cache gradualmente para evitar limites do descritor de arquivo
Variáveis ajustar:
query_cache_size (> = 8M)
thread_cache_size (inicie em 4)
table_cache (> 64)

Observe nas métricas de desempenho

[-] Total de buffers: 34,0M globais + 2,7M por thread (1050 max de threads)

que o MySQL pode alocar até 72% da RAM instalada com base nas configurações em /etc/my.cnf.

O 34M é baseado em innodb_buffer_pool_size e key_buffer_size combinados

Os 2,7 milhões por segmento foram baseados em read_buffer_size + read_rnd_buffer_size + sort_buffer_size + join_buffer_size.

Múltiplos de 2,7 milhões são baseados em max_connections.

Portanto, você deve alterar esses parâmetros até que o relatório de métricas de desempenho indique que você possui menos de 100% (preferencialmente menos de 80%) da RAM instalada.

RolandoMySQLDBA
fonte
Não tenho certeza se posso usar sua ferramenta; Estou usando o Windows. A documentação mencionava que o Windows não é suportado, mas tentei assim mesmo. Quando tentei executá-lo, ele indicou que não conseguia encontrar o mysqladmin no meu $ PATH, mas o diretório bin do MySQL está realmente no meu $ PATH.
Michael McGowan
Desculpe, não notei o datadir do Windows. Vou adicionar uma resposta diferente.
RolandoMySQLDBA 28/03
1

Você não disse quanta RAM você tem? Presumo que seja pelo menos 32 GB.

innodb_buffer_pool_size - 23G

Bom para tanta memória RAM.

query_cache_size = 1G

Grande demais. É ineficiente quando é grande. Recomende não mais que 50 milhões.

key-buffer_size = 5G

Pode haver um limite rígido de 4G (ainda) no Windows, um limite rígido de 4G. Seu 5G pode ter se transformado em 1G. Enfim, se todas as suas mesas são InnoDB, por que desperdiçar o carneiro? Defina para 50M.

Desde que a mensagem de erro tinha exatamente 1G, cheira a sort_buffer_size. 32M pode ser razoável.

Rick James
fonte