Por que os SELECTs simples no InnoDB 100x são mais lentos que no MyISAM?

33

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.

jollyroger
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Paul White diz GoFundMonica

Respostas:

24

SUA PERGUNTA

SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506;

À primeira vista, essa consulta deve tocar apenas 1,1597% (62510 de 5390146) da tabela. Deve ser rápido, dada a distribuição de chaves do threadid 51506.

VERIFICAÇÃO DA REALIDADE

Não importa qual versão do MySQL (Oracle, Percona, MariaDB) você use, nenhum deles pode lutar contra um inimigo que todos eles têm em comum: a arquitetura InnoDB.

Arquitetura InnoDB

ÍNDICE CLUSTERED

Lembre-se de que cada entrada de thread tem uma chave primária anexada. Isso significa que, quando você lê o índice, ele deve fazer uma pesquisa de chave primária no ClusteredIndex (denominado internamente gen_clust_index) . No ClusteredIndex, cada página do InnoDB contém dados e informações sobre o índice PRIMARY KEY. Veja minha postagem Best of MyISAM e InnoDB para mais informações.

ÍNDICES REDUNDANTES

Você tem muita confusão na tabela porque alguns índices têm as mesmas colunas iniciais. O MySQL e o InnoDB precisam navegar pela confusão de índices para obter os nós BTREE necessários. Você deve reduzir essa confusão executando o seguinte:

ALTER TABLE newbb_innopost
    DROP INDEX threadid,
    DROP INDEX threadid_2,
    DROP INDEX threadid_visible_dateline,
    ADD INDEX threadid_visible_dateline_index (`threadid`,`visible`,`dateline`,`userid`)
;

Por que reduzir esses índices?

  • Os três primeiros índices começam com threadid
  • threadid_2e threadid_visible_datelinecomece com as mesmas três colunas
  • threadid_visible_dateline não precisa de postid, pois é a CHAVE PRIMÁRIA e está incorporado

CACHING DE TAMPÃO

O InnoDB Buffer Pool armazena em cache dados e páginas de índice. O MyISAM apenas armazena em cache as páginas de índice.

Apenas nesta área, o MyISAM não perde tempo armazenando dados em cache. Isso porque não foi projetado para armazenar dados em cache. O InnoDB armazena em cache todas as páginas de dados e páginas de índice (e sua avó) em que toca. Se o seu InnoDB Buffer Pool for muito pequeno, você poderá fazer cache de páginas, invalidar páginas e remover páginas em uma única consulta.

LAYOUT DE MESA

Você pode economizar algum espaço da linha considerando importthreadide importpostid. Você os tem como BIGINTs. Eles ocupam 16 bytes no ClusteredIndex por linha.

Você deve executar isso

SELECT importthreadid,importpostid FROM newbb_innopost PROCEDURE ANALYSE();

Isso recomendará quais tipos de dados essas colunas devem ser para o conjunto de dados fornecido.

CONCLUSÃO

O MyISAM tem muito menos a enfrentar do que o InnoDB, especialmente na área de cache.

Enquanto você revelou a quantidade de RAM ( 32GB) e a versão do MySQL ( Server version: 10.0.12-MariaDB-1~trusty-wsrep-log mariadb.org binary distribution, wsrep_25.10.r4002), ainda existem outras peças neste quebra-cabeça que você não revelou.

  • As configurações do InnoDB
  • O número de núcleos
  • Outras configurações de my.cnf

Se você pode adicionar essas coisas à pergunta, eu posso aprofundar.

ATUALIZAÇÃO 28-08-2014 11:27 EDT

Você deve aumentar a segmentação

innodb_read_io_threads = 64
innodb_write_io_threads = 16
innodb_log_buffer_size = 256M

Eu consideraria desabilitar o cache de consultas (Veja minha postagem recente Por que query_cache_type está desativado por padrão, inicie no MySQL 5.6? )

query_cache_size = 0

Eu preservaria o Buffer Pool

innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1

Aumente os threads de limpeza (se você fizer DML em várias tabelas)

innodb_purge_threads = 4

DE UMA CHANCE !!!

RolandoMySQLDBA
fonte
Eu sei que o InnoDB deve ser mais lento em um teste de velocidade pura, mas nessa medida? Eu li que a equipe do MySQL tem trabalhado duro para fechar essa lacuna. Ainda estamos lidando com um aumento de ~ 100 vezes! Pergunta - você está dizendo que consultas dessa natureza seriam melhor atendidas com um índice de árvore B não-cluster "direto" (ou seja, sem os dados de PK incluídos)? Se sim, por que não foi / não foi / está sendo implementado? A funcionalidade que o OP exige definitivamente não é um caso de uso marginal.
Vérace
Você pode adicionar um link para a versão em tamanho real dessa imagem? Algumas peças são difíceis de ler :-)
aguado
@RolandMySQLDBA obrigado pela informação - espero que você não esteja sugerindo que uma desaceleração de 100x seja "normal" para o InnoDB ... Eu poderia viver com 2x ou 3x, mas 100x é simplesmente demais. Conforme solicitado, adicionei as informações ausentes à minha pergunta :) Obrigado pelas explicações até agora! Número de núcleos da máquina é de 8.
jollyroger
2
@watery Aqui está a Full Size Imagem: scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing
RolandoMySQLDBA
1
Muito obrigado pela sua ajuda @RolandoMySQLDBA, infelizmente, mesmo os últimos ajustes não ajudaram, e o InnoDB leva cerca de 11 a 20 segundos para ser concluído. Eu tentei algo com base na sua resposta - eliminando todos os índices e criando um índice de cobertura. Isso ajudou muito. Sem a sua explicação dos índices, eu não teria encontrado esta solução. Indo para verificar sua resposta e escrever uma resposta me explicar o que eu fiz :)
jollyroger
7

O @RolandMySQLDBA deu a dica certa para responder à pergunta. O problema parece estar na consulta e, para que os resultados sejam devolvidos, cada um desses campos precisa ser lido (de alguma forma no banco de dados).

Larguei todos os índices, exceto o PRIMARY KEY, e inseri este novo índice:

ALTER TABLE newbb_innopost ADD INDEX threadid_visible_dateline_index (threadid,visible,dateline,userid,attach,ipaddress);

Este link explica o que acontece aqui ( índice de cobertura ): Os campos consultados da consulta postid,attachagora podem ser extraídos da própria chave. Isso economiza a verificação dos dados reais e o uso de E / S no disco rígido.

Todas as consultas agora são executadas com 0,00 segundos .. :)

Muito obrigado por sua ajuda.

Edit : O problema subjacente real não foi resolvido, eu apenas o contornei com esta técnica. O InnoDB precisa de uma correção séria nesta área.

jollyroger
fonte
eu estou enfrentando o mesmo problema. A consulta myisma leva 0,01 segundos enquanto o innodb leva 60 segundos, tentarei suas sugestões.
AMB
@AMB - 0,01s tem cheiro de cache de consulta; cronometre novamente com SQL_NO_CACHE.
Rick James
0

Com base na consulta e na tabela, parece que você seleciona dados de uma tabela de séries temporais. Como tal, pode ser que o tempo de consulta seja lento porque você está inserindo simultaneamente?

Se essas duas coisas são verdadeiras, posso sugerir que você procure no ScaleDB como uma alternativa? Você ainda estará no MariaDB, apenas (talvez) um mecanismo mais apropriado.

http://www.scaledb.com - Página inicial http://www.scaledb.com/download-form.php - nosso produto

OShadmon
fonte
2
Você deve adicionar que a edição principal não é gratuita.
ypercubeᵀᴹ
0

Ambos os mecanismos executarão a consulta muito mais rapidamente com

INDEX(threadid, attach, postid)

Isso ocorre porque será um índice de "cobertura" e funcionará praticamente da mesma maneira (usando o índice BTree).

Além disso, direi que isso não é possível para nenhum mecanismo em um servidor "frio":

62510 rows in set (0.13 sec)

Use SQL_NO_CACHEsempre que estiver executando os horários - não queremos que o cache de consultas polua as conclusões.

Outra abordagem rápida (independentemente do cache de E / S):

Use o InnoDB e mude de PRIMARY KEY (postid)para

PRIMARY KEY(threadid, postid),
INDEX(postid)

O motivo é que isso fará com que todas as linhas relevantes sejam adjacentes, exigindo menos E / S, etc. O INDEX(postid)objetivo é manter-se AUTO_INCREMENTfeliz. Advertência: Isso mexe com todas as teclas secundárias - algumas serão mais rápidas, outras serão mais lentas.

Rick James
fonte
0

Embora não seja diretamente aplicável ao @jollyroger, porque ele já possui a configuração correta, mas obtive uma grande melhoria ao mudar innodb_buffer_pool_sizepara 70% da minha RAM, conforme explicado em Por que o myisam é mais lento que o Innodb

Primeiro MyISAMfoi lento, mas ok. Em seguida, InnoDBtornou as coisas ruins, semelhante ao 100x mais lento nesta questão e, depois de alterar a configuração, InnoDBficou 10 vezes mais rápido MyISAM.

Minha configuração padrão era 8 MB, que é muito pequena.

Hugo Delsing
fonte