Eu tenho um problema bastante irritante. Quero usar o INNODB como meu principal mecanismo de banco de dados e desistir do MyISAM, pois preciso do primeiro para usar o galera-cluster para redundância.
Copiei (descrição a seguir) a newbb_posttabela para uma nova tabela chamada newbb_innoposte alterei para InnoDB. As tabelas atualmente contêm 5,390,146entradas cada.
Ao executar essas seleções em um banco de dados recém-iniciado (portanto, nenhum cache está envolvido neste momento!), O banco de dados produz os seguintes resultados (omitindo a saída completa, observe que eu nem peço ao banco de dados para classificar os resultados):
SELECT post.postid, post.attach FROM newbb_post AS post WHERE post.threadid = 51506; . . | 5401593 0 | 5401634 0 + --------- + -------- + 62510 linhas no conjunto (0,13 s)
SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; . . | 5397410 0 | 5397883 0 + --------- + -------- + 62510 linhas em conjunto (1 min 22,19 s)
0,13 segundos a 86,19 segundos (!)
Eu estou querendo saber por que isso está acontecendo. Eu li algumas respostas aqui no Stackexchange envolvendo o InnoDB e algumas sugerem aumentar o innodb_buffer_pooltamanho para 80% da RAM instalada. Isso não resolverá o problema: a consulta inicial a um ID específico levará pelo menos 50 vezes mais tempo e paralisará toda a web, enfileirando conexões e consultas para o banco de dados. Posteriormente, o cache / buffer pode entrar, mas há mais de 100.000 threads neste banco de dados, portanto, é muito provável que o cache nunca retenha todas as consultas relevantes a serem atendidas.
As consultas acima são simples (sem junções) e todas as chaves são usadas:
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | id | select_type | mesa | tipo | possible_keys | chave key_len | ref linhas | Extra | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | 1 | SIMPLES | postar | ref threadid, threadid_2, threadid_visible_dateline | threadid | 4 const 120144 | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
Esta é a tabela MyISAM:
CREATE TABLE `newbb_post` (
`postid` int (10) não assinado NOT NULL AUTO_INCREMENT,
`threadid` int (10) não assinado NOT NULL DEFAULT '0',
`parentid` int (10) não assinado NOT NULL DEFAULT '0',
`username` varchar (100) NÃO NULL PADRÃO '',
`userid` int (10) não assinado NOT NULL DEFAULT '0',
`title` varchar (250) NÃO NULL PADRÃO '',
`dateline` int (10) não assinado NOT NULL DEFAULT '0',
`pagetext` texto médio,
`allowmilie` smallint (6) NÃO NULL PADRÃO '0',
`showsignature` smallint (6) NÃO NULL DEFAULT '0',
`ipaddress` varchar (15) NÃO NULL PADRÃO '',
`iconid` smallint (5) não assinado NOT NULL DEFAULT '0',
`visible` smallint (6) NÃO NULL PADRÃO '0',
`attach` smallint (5) não assinado NOT NULL DEFAULT '0',
`infraction` smallint (5) não assinado NOT NULL DEFAULT '0',
`reportthreadid` int (10) não assinado NOT NULL DEFAULT '0',
`importthreadid` bigint (20) NÃO NULL PADRÃO '0',
`importpostid` bigint (20) NÃO NULL DEFAULT '0',
`convert_2_utf8` int (11) NÃO NULL,
`htmlstate` enum ('off', 'on', 'on_nl2br') NÃO NULL PADRÃO 'on_nl2br',
CHAVE PRIMÁRIA (`postid`),
KEY `threadid` (` threadid`, `userid`),
KEY `importpost_index` (` importpostid`),
KEY `linha de dados` (` linha de dados`),
KEY `threadid_2` (` threadid`, `visible`,` dateline`),
KEY `convertido_2_utf8` (` convertido_2_utf8`),
KEY `threadid_visible_dateline` (` threadid`, `visible`,` dateline`, `userid`,` postid`),
KEY `ipaddress` (` ipaddress`),
KEY `userid` (` userid`, `parentid`),
KEY `data_do_usuário` (` ID do usuário`, `linha de dados`)
) MOTOR = MyISAM AUTO_INCREMENT = 5402802 CHARSET PADRÃO = latin1
e esta é a tabela InnoDB (é exatamente a mesma):
CREATE TABLE `newbb_innopost` (
`postid` int (10) não assinado NOT NULL AUTO_INCREMENT,
`threadid` int (10) não assinado NOT NULL DEFAULT '0',
`parentid` int (10) não assinado NOT NULL DEFAULT '0',
`username` varchar (100) NÃO NULL PADRÃO '',
`userid` int (10) não assinado NOT NULL DEFAULT '0',
`title` varchar (250) NÃO NULL PADRÃO '',
`dateline` int (10) não assinado NOT NULL DEFAULT '0',
`pagetext` texto médio,
`allowmilie` smallint (6) NÃO NULL PADRÃO '0',
`showsignature` smallint (6) NÃO NULL DEFAULT '0',
`ipaddress` varchar (15) NÃO NULL PADRÃO '',
`iconid` smallint (5) não assinado NOT NULL DEFAULT '0',
`visible` smallint (6) NÃO NULL PADRÃO '0',
`attach` smallint (5) não assinado NOT NULL DEFAULT '0',
`infraction` smallint (5) não assinado NOT NULL DEFAULT '0',
`reportthreadid` int (10) não assinado NOT NULL DEFAULT '0',
`importthreadid` bigint (20) NÃO NULL PADRÃO '0',
`importpostid` bigint (20) NÃO NULL DEFAULT '0',
`convert_2_utf8` int (11) NÃO NULL,
`htmlstate` enum ('off', 'on', 'on_nl2br') NÃO NULL PADRÃO 'on_nl2br',
CHAVE PRIMÁRIA (`postid`),
KEY `threadid` (` threadid`, `userid`),
KEY `importpost_index` (` importpostid`),
KEY `linha de dados` (` linha de dados`),
KEY `threadid_2` (` threadid`, `visible`,` dateline`),
KEY `convertido_2_utf8` (` convertido_2_utf8`),
KEY `threadid_visible_dateline` (` threadid`, `visible`,` dateline`, `userid`,` postid`),
KEY `ipaddress` (` ipaddress`),
KEY `userid` (` userid`, `parentid`),
KEY `data_do_usuário` (` ID do usuário`, `linha de dados`)
) MOTOR = InnoDB AUTO_INCREMENT = 5402802 CHARSET PADRÃO = latin1
Servidor, com 32 GB de RAM:
Versão do servidor: 10.0.12-MariaDB-1 ~ distribuição binária triad-wsrep-log mariadb.org, wsrep_25.10.r4002
Se você precisar de todas as configurações de variáveis innodb_, posso anexar isso a este post.
Atualizar:
Larguei TODOS os índices além do índice primário, depois o resultado ficou assim:
. . | 5402697 | 0 | 5402759 0 + --------- + -------- + 62510 linhas no conjunto (29,74 seg)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | id | select_type | mesa | tipo | possible_keys | chave key_len | ref linhas | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | 1 | SIMPLES | postar | TUDO | NULL NULL NULL NULL 5909836 Usando onde | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + 1 linha no conjunto (0,00 s)
Depois disso, eu apenas adicionei um índice de volta ao mix, threadid, os resultados foram os seguintes:
. . | 5402697 | 0 | 5402759 0 + --------- + -------- + 62510 linhas no conjunto (11,58 seg)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | id | select_type | mesa | tipo | possible_keys | chave key_len | ref linhas | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | 1 | SIMPLES | postar | ref threadid | threadid | 4 const 124622 | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + 1 linha no conjunto (0,00 s)
Estranho é que, sem índices relevantes, a verificação completa levou apenas 29 segundos em comparação com os 88 segundos usando índices (!).
Com apenas um índice perfeitamente adaptado, ainda está demorando 11 segundos para ser concluído - ainda é muito lento para qualquer uso no mundo real.
Atualização 2:
Eu configurei o MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) em outro servidor com exatamente a mesma configuração de hardware e exatamente o mesmo banco de dados / tabelas.
Os resultados são quase os mesmos, primeiro a tabela MyISAM:
. . | 5401593 0 | 5401634 0 + --------- + -------- + 62510 linhas no conjunto (0,14 s)
E este é o resultado da tabela InnoDB
. . | 5397410 0 | 5397883 0 + --------- + -------- + 62510 linhas em conjunto (1 min 17,63 seg)
ATUALIZAÇÃO 3: o conteúdo do my.cnf
# Arquivo de configuração do servidor de banco de dados MariaDB.
#
# Você pode copiar este arquivo para um dos seguintes:
# - "/etc/mysql/my.cnf" para definir opções globais,
# - "~ / .my.cnf" para definir opções específicas do usuário.
#
# Pode-se usar todas as opções longas suportadas pelo programa.
# Execute o programa com --help para obter uma lista de opções disponíveis e com
# --print-default para ver qual ele realmente entenderia e usaria.
#
# Para explicações, consulte
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
# Isso será passado para todos os clientes mysql
# Foi relatado que as senhas devem ser colocadas com carrapatos / aspas
# especialmente se eles contêm caracteres "#" ...
# Lembre-se de editar o /etc/mysql/debian.cnf ao alterar a localização do soquete.
[cliente]
port = 3306
socket = /var/run/mysqld/mysqld.sock
# Aqui estão as entradas para alguns programas específicos
# Os seguintes valores assumem que você tem pelo menos 32M de RAM
# Isso foi formalmente conhecido como [safe_mysqld]. As duas versões estão atualmente analisadas.
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
#
# * Configurações básicas
#
usuário = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = / usr
datadir = / var / lib / mysql
tmpdir = / tmp
lc_messages_dir = / usr / share / mysql
lc_messages = pt_BR
pular bloqueio externo
#
# Em vez de pular a rede, o padrão agora é ouvir apenas em
# localhost, que é mais compatível e não é menos seguro.
endereço de ligação = 127.0.0.1
#
# * Afinação
#
max_connections = 100
connect_timeout = 5
wait_timeout = 600
max_allowed_packet = 16M
thread_cache_size = 128
sort_buffer_size = 4M
bulk_insert_buffer_size = 16M
tmp_table_size = 32M
max_heap_table_size = 32M
#
# * MyISAM
#
# Isso substitui o script de inicialização e verifica as tabelas MyISAM, se necessário
# na primeira vez em que são tocados. Em caso de erro, faça uma cópia e tente um reparo.
myisam_recover = BACKUP
key_buffer_size = 128M
# open-files-limit = 2000
table_open_cache = 400
myisam_sort_buffer_size = 512M
concurrent_insert = 2
read_buffer_size = 2M
read_rnd_buffer_size = 1M
#
# * Configuração do cache de consulta
#
# Armazenar em cache apenas pequenos conjuntos de resultados, para que possamos ajustar mais no cache de consultas.
query_cache_limit = 128K
query_cache_size = 64M
# para configurações mais intensivas de gravação, defina como DEMAND ou OFF
#query_cache_type = DEMANDA
#
# * Log e replicação
#
# Ambos os locais são rotacionados pelo cronjob.
# Esteja ciente de que esse tipo de log é prejudicial ao desempenho.
# A partir da versão 5.1, você pode ativar o log em tempo de execução!
#general_log_file = /var/log/mysql/mysql.log
#general_log = 1
#
# O log de erros vai para o syslog devido a /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
#
# queremos saber sobre erros de rede e tais
log_warnings = 2
#
# Ative o log de consultas lento para ver consultas com duração especialmente longa
#slow_query_log [= {0 | 1}]
slow_query_log_file = /var/log/mysql/mariadb-slow.log
long_query_time = 10
#log_slow_rate_limit = 1000
log_slow_verbosity = query_plan
# log-queries-not-using-indexes
#log_slow_admin_statements
#
# O seguinte pode ser usado como fácil para reproduzir logs de backup ou para replicação.
# note: se você estiver configurando um escravo de replicação, consulte README.Debian sobre
# outras configurações que você precise alterar.
# server-id = 1
#report_host = master1
#auto_increment_increment = 2
#auto_increment_offset = 1
log_bin = / var / log / mysql / mariadb-bin
log_bin_index = /var/log/mysql/mariadb-bin.index
# não fabuloso por desempenho, mas mais seguro
#sync_binlog = 1
expire_logs_days = 10
max_binlog_size = 100M
# escravos
#relay_log = / var / log / mysql / relay-bin
#relay_log_index = /var/log/mysql/relay-bin.index
#relay_log_info_file = /var/log/mysql/relay-bin.info
#log_slave_updates
#somente leitura
#
# Se os aplicativos suportarem, esse sql_mode mais restrito evita que alguns
# erros como inserir datas inválidas etc.
#sql_mode = NO_ENGINE_SUBSTITUTION, TRADICIONAL
#
# * InnoDB
#
# O InnoDB é ativado por padrão com um arquivo de dados de 10 MB em / var / lib / mysql /.
# Leia o manual para obter mais opções relacionadas ao InnoDB. Há muitos!
default_storage_engine = InnoDB
# você não pode simplesmente alterar o tamanho do arquivo de log, requer procedimento especial
#innodb_log_file_size = 50M
innodb_buffer_pool_size = 20G
innodb_log_buffer_size = 8M
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 400
innodb_flush_method = O_DIRECT
#
# * Recursos de segurança
#
# Leia o manual também, se você quiser chroot!
# chroot = / var / lib / mysql /
#
# Para gerar certificados SSL, recomendo a interface gráfica do usuário OpenSSL "tinyca".
#
# ssl-ca = / etc / mysql / cacert.pem
# ssl-cert = / etc / mysql / server-cert.pem
# ssl-key = / etc / mysql / server-key.pem
[mysqldump]
rápido
aspas
max_allowed_packet = 16M
[mysql]
# no-auto-rehash # início mais rápido do mysql, mas nenhuma conclusão de guia
[isamchk]
key_buffer = 16M
#
# * IMPORTANTE: Configurações adicionais que podem substituir as deste arquivo!
# Os arquivos devem terminar com '.cnf', caso contrário, serão ignorados.
#
! includedir /etc/mysql/conf.d/
E o conteúdo das variáveis inno:
MariaDB [(nenhum)]> MOSTRAR VARIÁVEIS COMO 'inno%'; + ------------------------------------------- + ----- ------------------- + | Nome da variável | Valor + ------------------------------------------- + ----- ------------------- + | innodb_adaptive_flushing | ON | | innodb_adaptive_flushing_lwm | 10 | innodb_adaptive_hash_index | ON | | innodb_adaptive_hash_index_partitions | 1 | | innodb_adaptive_max_sleep_delay | 150000 | innodb_additional_mem_pool_size | 8388608 | innodb_api_bk_commit_interval | 5 | innodb_api_disable_rowlock | OFF | | innodb_api_enable_binlog | OFF | | innodb_api_enable_mdl | OFF | | innodb_api_trx_level | 0 | innodb_autoextend_increment | 64 | innodb_autoinc_lock_mode | 1 | | innodb_buffer_pool_dump_at_shutdown | OFF | | innodb_buffer_pool_dump_now | OFF | | innodb_buffer_pool_filename | ib_buffer_pool | | innodb_buffer_pool_instances | 8 | innodb_buffer_pool_load_abort | OFF | | innodb_buffer_pool_load_at_startup | OFF | | innodb_buffer_pool_load_now | OFF | | innodb_buffer_pool_populate | OFF | | innodb_buffer_pool_size | 21474836480 | | innodb_change_buffer_max_size | 25 | innodb_change_buffering | tudo | | innodb_checksum_algorithm | innodb | | innodb_checksums | ON | | innodb_cleaner_lsn_age_factor | high_checkpoint | | innodb_cmp_per_index_enabled | OFF | | innodb_commit_concurrency | 0 | innodb_compression_failure_threshold_pct | 5 | innodb_compression_level | 6 | innodb_compression_pad_pct_max | 50 | innodb_concurrency_tickets | 5000 | innodb_corrupt_table_action | afirmar | | innodb_data_file_path | ibdata1: 12M: autoextend | | innodb_data_home_dir | | | innodb_disable_sort_file_cache | OFF | | innodb_doublewrite | ON | | innodb_empty_free_list_algorithm | backoff | | innodb_fake_changes | OFF | | innodb_fast_shutdown | 1 | | innodb_file_format | Antílope | | innodb_file_format_check | ON | | innodb_file_format_max | Antílope | | innodb_file_per_table | ON | | innodb_flush_log_at_timeout | 1 | | innodb_flush_log_at_trx_commit | 1 | | innodb_flush_method | O_DIRECT | innodb_flush_neighbors | 1 | | innodb_flushing_avg_loops | 30 | innodb_force_load_corrupted | OFF | | innodb_force_recovery | 0 | innodb_foreground_preflush | exponential_backoff | | innodb_ft_aux_table | | | innodb_ft_cache_size | 8000000 | innodb_ft_enable_diag_print | OFF | | innodb_ft_enable_stopword | ON | | innodb_ft_max_token_size | 84 | innodb_ft_min_token_size | 3 | innodb_ft_num_word_optimize | 2000 | innodb_ft_result_cache_limit | 2000000000 | innodb_ft_server_stopword_table | | | innodb_ft_sort_pll_degree | 2 | innodb_ft_total_cache_size | 640000000 | innodb_ft_user_stopword_table | | | innodb_io_capacity | 400 | innodb_io_capacity_max | 2000 | innodb_kill_idle_transaction | 0 | innodb_large_prefix | OFF | | innodb_lock_wait_timeout | 50 | innodb_locking_fake_changes | ON | | innodb_locks_unsafe_for_binlog | OFF | | innodb_log_arch_dir | ./ | innodb_log_arch_expire_sec | 0 | innodb_log_archive | OFF | | innodb_log_block_size | 512 | innodb_log_buffer_size | 8388608 | innodb_log_checksum_algorithm | innodb | | innodb_log_compressed_pages | ON | | innodb_log_file_size | 50331648 | | innodb_log_files_in_group | 2 | innodb_log_group_home_dir | ./ | innodb_lru_scan_depth | 1024 | innodb_max_bitmap_file_size | 104857600 | | innodb_max_changed_pages | 1000000 | innodb_max_dirty_pages_pct | 75 | innodb_max_dirty_pages_pct_lwm | 0 | innodb_max_purge_lag | 0 | innodb_max_purge_lag_delay | 0 | innodb_mirrored_log_groups | 1 | | innodb_monitor_disable | | | innodb_monitor_enable | | | innodb_monitor_reset | | | innodb_monitor_reset_all | | | innodb_old_blocks_pct | 37 | innodb_old_blocks_time | 1000 | innodb_online_alter_log_max_size | 134217728 | | innodb_open_files | 400 | innodb_optimize_fulltext_only | OFF | | innodb_page_size | 16384 | innodb_print_all_deadlocks | OFF | | innodb_purge_batch_size | 300 | innodb_purge_threads | 1 | | innodb_random_read_ahead | OFF | | innodb_read_ahead_threshold | 56 | innodb_read_io_threads | 4 | innodb_read_only | OFF | | innodb_replication_delay | 0 | innodb_rollback_on_timeout | OFF | | innodb_rollback_segments | 128 | innodb_sched_priority_cleaner | 19 | innodb_show_locks_held | 10 | innodb_show_verbose_locks | 0 | innodb_sort_buffer_size | 1048576 | innodb_spin_wait_delay | 6 | innodb_stats_auto_recalc | ON | | innodb_stats_method | nulls_equal | | innodb_stats_on_metadata | OFF | | innodb_stats_persistent | ON | | innodb_stats_persistent_sample_pages | 20 | innodb_stats_sample_pages | 8 | innodb_stats_transient_sample_pages | 8 | innodb_status_output | OFF | | innodb_status_output_locks | OFF | | innodb_strict_mode | OFF | | innodb_support_xa | ON | | innodb_sync_array_size | 1 | | innodb_sync_spin_loops | 30 | innodb_table_locks | ON | | innodb_thread_concurrency | 0 | innodb_thread_sleep_delay | 10000 | innodb_track_changed_pages | OFF | | innodb_undo_directory | . | | innodb_undo_logs | 128 | innodb_undo_tablespaces | 0 | innodb_use_atomic_writes | OFF | | innodb_use_fallocate | OFF | | innodb_use_global_flush_log_at_trx_commit | ON | | innodb_use_native_aio | ON | | innodb_use_stacktrace | OFF | | innodb_use_sys_malloc | ON | | innodb_version | 5.6.17-65.0 | innodb_write_io_threads | 4 + ------------------------------------------- + ----- ------------------- + 143 linhas em conjunto (0,02 s)
O número de núcleos da máquina é 8, é um
Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz a partir de /proc/cpuinfo
Uma última observação: executou as consultas com os índices sugeridos pelo RolandoMYSQLDBA e as consultas demoraram cerca de 11 a 20s cada. Quero ressaltar que é crucial para mim (esta é a tabela principal de um quadro de avisos) que a primeira consulta sobre um threadid retorne em menos de um segundo, pois existem mais de 60.000 threads e o google-bots constantemente rastreia esses tópicos.
