Gravações Lentas do MySQL

8

As inserções na tabela a seguir estão demorando até 70 segundos para serem concluídas:

CREATE TABLE IF NOT EXISTS `productsCategories` (
  `categoriesId` int(11) NOT NULL,
  `productsId` int(11) NOT NULL,
  PRIMARY KEY (`categoriesId`,`productsId`),
  KEY `categoriesId` (`categoriesId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Existem cerca de 100.000 linhas na tabela, e está tomando 7 MB no disco.

Existem algumas configurações no MySQL que podem melhorar o desempenho da gravação?

Meu my.cnfarquivo é o seguinte:

log-slow-queries="/var/log/mysql/slow-query.log"
long_query_time=1 
log-queries-not-using-indexes

innodb_buffer_pool_size=4G
innodb_log_buffer_size=4M
innodb_flush_log_at_trx_commit=2
innodb_thread_concurrency=8
innodb_flush_method=O_DIRECT

query_cache_size = 6G
key_buffer_size = 284M
query_cache_limit = 1024M
thread_cache_size = 128
table_cache = 12800

sort_buffer_size=2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M

read_buffer_size=128K

open_files_limit               = 1000
table_definition_cache         = 1024
table_open_cache               = 6000

max_heap_table_size=512M
tmp_table_size=4096M

max_connections=1000

thread_concurrency = 24

Aqui está a configuração do hardware:

  • Dell R710
  • RAID10
  • 48G RAM

Dado esse hardware, eu não esperaria que o problema fosse um gargalo de hardware.

Ronn0
fonte
Você pode fornecer alguns dados objetivos? Registros, sua metodologia de teste / benchmarking e resultados, esse tipo de coisa?
Womble
Que tipo de logs você gostaria de ver? A única coisa que vejo por que demora tanto tempo é no mtop . Eu testaria coisas como alterar a tabela para uma tabela myisam, limites de memória mais altos, threads mais altos.
Ronn0
A melhor definição para melhorar mysql ... é mudar para postgres lol
Antony Gibbs
thread_concurrency = 24 não tem nenhum efeito ... você pode despejar essa linha
Antony Gibbs

Respostas:

16

OBSERVAÇÃO Nº 1

A primeira coisa que chama minha atenção é a estrutura da mesa

CREATE TABLE IF NOT EXISTS `productsCategories` (
  `categoriesId` int(11) NOT NULL,
  `productsId` int(11) NOT NULL,
  PRIMARY KEY (`categoriesId`,`productsId`),
  KEY `categoriesId` (`categoriesId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Observe que o categoriesIdíndice e a PRIMARY KEY começam com a mesma coluna. É um índice redundante. Como esta tabela é InnoDB, o categoriesIdíndice é redundante por outro motivo: Todos os índices secundários contêm chaves em gen_clust_index (também conhecido como Índice Clusterizado; Veja para que é usado gen_clust_index no mysql? )

Se você remover o categoriesIdíndice com

ALTER TABLE productsCategories DROP INDEX categoriesId;

isso melhorará drasticamente os INSERTs porque não é necessário fazer manutenção extra de índice secundário e em cluster.

OBSERVAÇÃO Nº 2

Se você estiver executando alguma operação de inserção em massa, precisará de um buffer grande de inserção em massa .

Por favor, veja minhas postagens anteriores sobre isso:

OBSERVAÇÃO Nº 3

O tamanho do seu arquivo de log é muito pequeno !!! Deve ser 25% do InnoDB Buffer Pool, que no seu caso deve ser 1G. Veja meu post sobre como redimensionar arquivos de log do InnoDB .

OBSERVAÇÃO Nº 4

Por favor, não defina innodb_thread_concurrency !!! Aprendi em primeira mão no Percona Live NYC a deixar esse cenário em paz . Ele está desativado por padrão no MySQL 5.5, MySQL 5.1 InnoDB Plugin e Percona Server 5.1 ou superior.

OBSERVAÇÃO Nº 5

Você precisa usar innodb_file_per_table. Se isso estiver desativado, tornarei a manutenção de arquivos no ibdata1 um pesadelo. Leia meu post sobre como limpar o InnoDB para implementar isso .

OBSERVAÇÃO Nº 6

Se você estiver usando o MySQL 5.5 ou o Percona Server, precisará definir certas opções para fazer com que o InnoDB use CPUs múltiplas / múltiplos núcleos. Por favor, veja o meu post sobre essas configurações .

OBSERVAÇÃO Nº 7

Você tem innodb_log_buffer_size=4M. O padrão é 8M. Isso causará o dobro de descarga nos logs de refazer. Isso também irá neutralizar sua innodb_flush_log_at_trx_commit=2configuração. Defina-o para 32 milhões. Além disso, consulte a documentação do MySQL em innodb_log_buffer_size .

À luz dessas observações, adicione ou substitua as seguintes configurações:

[mysqld]
innodb_thread_concurrency = 0
innodb_read_io_threads = 64
innodb_write_io_threads = 64
innodb_io_capacity = 5000
innodb_file_per_table
innodb_log_file_size=1G
innodb_log_buffer_size=1G
bulk_insert_buffer_size = 256M
RolandoMySQLDBA
fonte
Uau, obrigada! Eu imprimi todos os pontos e trabalhei nele agora e salvei no cérebro para ajudar outras pessoas no futuro. Muito Obrigado!
Ronn0
2
query_cache_sizeé enorme também. Cada inserção exigirá a liberação de até 6 GB de cache.
Aaron Brown
@AaronBrown Eu concordo. Li no livro MySQL de alto desempenho que o InnoDB faz coisas tediosas com o ID da transação na tabela do InnoDB no cache de consultas, o que torna desnecessário, para não mencionar lento, o uso de um cache de consultas. De fato, o MySQL 4.1 tem o cache de consultas desativado para o InnoDB.
RolandoMySQLDBA
Eu acho que o cache da consulta é completamente separado do mecanismo de armazenamento. Basicamente, serializa todas as operações de gravação, forçando tudo a passar e varre o cache de consultas para invalidar consultas. Eu nunca encontrei um caso de uso para ele e sempre causava problemas.
Aaron Brown
mais uma coisa a acrescentar: query_cache_size = 6G <- isso é total e totalmente absurdo. O cache de consulta geralmente é melhor desativado e, com certeza, não deve ser mais do que 32M ou 64M. A sobrecarga de manter um cache de consulta 6G certamente está prejudicando o desempenho.
Gavin Towey
0

Você deve verificar innodb_log_file_size, a configuração padrão é 5M, que é bastante baixa para configurações intensivas de gravação. Considere configurá-lo para 100M. Você precisará excluir os ib_logfile*arquivos antigos para iniciar o banco de dados com novas configurações. Por favor, não exclua os arquivos de log enquanto o servidor de banco de dados estiver em execução; será necessário interrompê-lo primeiro. Provavelmente você deve primeiro fazer backup dos arquivos de log antigos, não apenas excluí-los.

Alex
fonte