Perché i semplici SELECT su InnoDB 100x sono più lenti rispetto a MyISAM?


33

Ho un problema piuttosto fastidioso. Voglio usare INNODB come motore di database principale e rinunciare a MyISAM poiché ho bisogno del primo per usare il cluster galera per la ridondanza.

Ho copiato (la descrizione segue) la newbb_posttabella in una nuova tabella chiamata newbb_innoposte l' ho cambiata in InnoDB. Le tabelle contengono attualmente 5,390,146voci ciascuna.

Eseguendo queste selezioni su un database appena avviato (quindi a questo punto non è coinvolta alcuna memorizzazione nella cache!) Il database produce i seguenti risultati (omettendo l'output completo, si noti che non chiedo nemmeno al database di ordinare i risultati):

SELEZIONA post.postid, post.attach DA newbb_post AS post DOVE post.threadid = 51506;

.
.
| 5401593 | 0 |
| 5401634 | 0 |
+ --------- + -------- +
62510 righe nel set (0,13 sec)
SELEZIONA post.postid, post.attach DA newbb_innopost AS post DOVE post.threadid = 51506;
.
.
| 5397410 | 0 |
| 5397883 | 0 |
+ --------- + -------- +
62510 righe nel set (1 min 22,19 sec)

Da 0,13 secondi a 86,19 secondi (!)

Mi chiedo perché questo stia accadendo. Ho letto alcune risposte qui su Stackexchange che coinvolge InnoDB e alcuni suggeriscono di aumentare le innodb_buffer_pooldimensioni all'80% della RAM installata. Ciò non risolverà il problema, poiché la query iniziale su un determinato ID richiederà almeno 50 volte più tempo e bloccherà l'intero websever, accodando connessioni e query per il database. Successivamente la cache / buffer potrebbe avviarsi, ma ci sono oltre 100.000 thread in questo database, quindi è molto probabile che la cache non conterrà mai tutte le query pertinenti da servire.

Le query sopra sono semplici (nessun join) e vengono utilizzate tutte le chiavi:

SPIEGA SELEZIONA post.postid, post.attach DA newbb_innopost AS post DOVE post.threadid = 51506;
+ ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
| id | select_type | tabella | digitare | possible_keys | chiave | key_len | rif | righe | Extra |
+ ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
| 1 | SEMPLICE | posta | rif | threadid, threadid_2, threadid_visible_dateline | threadid | 4 | const | 120144 | |
+ ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +

Questa è la tabella MyISAM:

CREATE TABLE `newbb_post` (
  `postid` int (10) unsigned NOT NULL AUTO_INCREMENT,
  `threadid` int (10) unsigned NOT NULL DEFAULT '0',
  `parentid` int (10) unsigned NOT NULL DEFAULT '0',
  `username` varchar (100) NOT NULL DEFAULT '',
  `userid` int (10) unsigned NOT NULL DEFAULT '0',
  `title` varchar (250) NOT NULL DEFAULT '',
  `dateline` int (10) unsigned NOT NULL DEFAULT '0',
  medium 'pagetext`,
  `allowmilie` smallint (6) NON NULL DEFAULT '0',
  `showsignature` smallint (6) NOT NULL DEFAULT '0',
  `ipaddress` varchar (15) NOT NULL DEFAULT '',
  `iconid` smallint (5) unsigned NOT NULL DEFAULT '0',
  `visible` smallint (6) NOT NULL DEFAULT '0',
  `attach` smallint (5) unsigned NOT NULL DEFAULT '0',
  `infraction` smallint (5) unsigned NOT NULL DEFAULT '0',
  `reportthreadid` int (10) unsigned NOT NULL DEFAULT '0',
  `importthreadid` bigint (20) NOT NULL DEFAULT '0',
  `importpostid` bigint (20) NOT NULL DEFAULT '0',
  `convert_2_utf8` int (11) NOT NULL,
  `htmlstate` enum ('off', 'on', 'on_nl2br') NON NULL DEFAULT 'on_nl2br',
  CHIAVE PRIMARIA (`postid`),
  KEY `threadid` (` threadid`, `userid`),
  KEY `importpost_index` (` importpostid`),
  KEY `dateline` (` dateline`),
  KEY `threadid_2` (` threadid`, `visible`,` dateline`),
  KEY `convert_2_utf8` (` convert_2_utf8`),
  KEY `threadid_visible_dateline` (` threadid`, `visible`,` dateline`, `userid`,` postid`),
  KEY `ipaddress` (` ipaddress`),
  KEY `userid` (` userid`, `parentid`),
  KEY `user_date` (` userid`, `dateline`)
) ENGINE = MyISAM AUTO_INCREMENT = 5402802 CARATTERISTICHE PREDEFINITE = latin1

e questa è la tabella InnoDB (è esattamente la stessa):

CREATE TABLE `newbb_innopost` (
  `postid` int (10) unsigned NOT NULL AUTO_INCREMENT,
  `threadid` int (10) unsigned NOT NULL DEFAULT '0',
  `parentid` int (10) unsigned NOT NULL DEFAULT '0',
  `username` varchar (100) NOT NULL DEFAULT '',
  `userid` int (10) unsigned NOT NULL DEFAULT '0',
  `title` varchar (250) NOT NULL DEFAULT '',
  `dateline` int (10) unsigned NOT NULL DEFAULT '0',
  medium 'pagetext`,
  `allowmilie` smallint (6) NON NULL DEFAULT '0',
  `showsignature` smallint (6) NOT NULL DEFAULT '0',
  `ipaddress` varchar (15) NOT NULL DEFAULT '',
  `iconid` smallint (5) unsigned NOT NULL DEFAULT '0',
  `visible` smallint (6) NOT NULL DEFAULT '0',
  `attach` smallint (5) unsigned NOT NULL DEFAULT '0',
  `infraction` smallint (5) unsigned NOT NULL DEFAULT '0',
  `reportthreadid` int (10) unsigned NOT NULL DEFAULT '0',
  `importthreadid` bigint (20) NOT NULL DEFAULT '0',
  `importpostid` bigint (20) NOT NULL DEFAULT '0',
  `convert_2_utf8` int (11) NOT NULL,
  `htmlstate` enum ('off', 'on', 'on_nl2br') NON NULL DEFAULT 'on_nl2br',
  CHIAVE PRIMARIA (`postid`),
  KEY `threadid` (` threadid`, `userid`),
  KEY `importpost_index` (` importpostid`),
  KEY `dateline` (` dateline`),
  KEY `threadid_2` (` threadid`, `visible`,` dateline`),
  KEY `convert_2_utf8` (` convert_2_utf8`),
  KEY `threadid_visible_dateline` (` threadid`, `visible`,` dateline`, `userid`,` postid`),
  KEY `ipaddress` (` ipaddress`),
  KEY `userid` (` userid`, `parentid`),
  KEY `user_date` (` userid`, `dateline`)
) ENGINE = InnoDB AUTO_INCREMENT = 5402802 CARATTERISTICHE PREDEFINITE = latin1

Server, con 32 GB di RAM:

Versione server: 10.0.12-MariaDB-1 ~ trusty-wsrep-log mariadb.org distribuzione binaria, wsrep_25.10.r4002

Se hai bisogno di tutte le impostazioni delle variabili innodb_, posso collegarle a questo post.

Aggiornare:

Ho lasciato cadere TUTTI gli indici dall'indice primario, in seguito il risultato è stato questo:

.
.
| 5402697 | 0 |
| 5402759 | 0 |
+ --------- + -------- +
62510 righe nel set (29,74 sec)
SPIEGA SELEZIONA post.postid, post.attach DA newbb_innopost AS post DOVE post.threadid = 51506;
+ ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- +
| id | select_type | tabella | digitare | possible_keys | chiave | key_len | rif | righe | Extra |
+ ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- +
| 1 | SEMPLICE | posta | TUTTO | NULL | NULL | NULL | NULL | 5909836 | Utilizzando dove |
+ ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- +
1 riga nel set (0,00 sec)

Dopo questo ho appena aggiunto un indice al mix, threadid, i risultati sono stati i seguenti:

.
.
| 5402697 | 0 |
| 5402759 | 0 |
+ --------- + -------- +
62510 righe nel set (11,58 sec)
SPIEGA SELEZIONA post.postid, post.attach DA newbb_innopost AS post DOVE post.threadid = 51506;
+ ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- +
| id | select_type | tabella | digitare | possible_keys | chiave | key_len | rif | righe | Extra |
+ ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- +
| 1 | SEMPLICE | posta | rif | threadid | threadid | 4 | const | 124622 | |
+ ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- +
1 riga nel set (0,00 sec)

È strano che, senza indici rilevanti, la scansione completa abbia richiesto solo 29 secondi rispetto agli 88 secondi usando gli indici (!).

Con un solo indice perfettamente su misura ci vogliono ancora 11 secondi per completarlo - ancora troppo lento per qualsiasi utilizzo nel mondo reale.

Aggiornamento 2:

Ho installato MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) su un altro server con la stessa identica configurazione hardware e esattamente lo stesso database / tabelle.

I risultati sono quasi gli stessi, prima la tabella MyISAM:

.
.
| 5401593 | 0 |
| 5401634 | 0 |
+ --------- + -------- +
62510 righe nel set (0,14 sec)

E questo è il risultato della tabella InnoDB

.
.
| 5397410 | 0 |
| 5397883 | 0 |
+ --------- + -------- +
62510 righe nel set (1 min 17,63 sec)

AGGIORNAMENTO 3: i contenuti di my.cnf

# File di configurazione del server di database MariaDB.
#
# È possibile copiare questo file in uno di:
# - "/etc/mysql/my.cnf" per impostare opzioni globali,
# - "~ / .my.cnf" per impostare opzioni specifiche dell'utente.
# 
# È possibile utilizzare tutte le opzioni lunghe supportate dal programma.
# Esegui il programma con --help per ottenere un elenco di opzioni disponibili e con
# --print-default per vedere quale effettivamente comprenderebbe e userebbe.
#
# Per le spiegazioni vedere
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

# Questo verrà passato a tutti i client mysql
# È stato segnalato che le password devono essere racchiuse tra segni di spunta / virgolette
# specialmente se contengono caratteri "#" ...
# Ricordarsi di modificare /etc/mysql/debian.cnf quando si cambia la posizione del socket.
[cliente]
porta = 3306
socket = /var/run/mysqld/mysqld.sock

# Ecco le voci per alcuni programmi specifici
# I seguenti valori presuppongono che tu abbia almeno 32 MB di RAM

# Questo era formalmente noto come [safe_mysqld]. Entrambe le versioni sono attualmente analizzate.
[Mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
bello = 0

[Mysqld]
#
# * Impostazioni di base
#
utente = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
porta = 3306
basedir = / usr
datadir = / var / lib / mysql
tmpdir = / tmp
lc_messages_dir = / usr / share / mysql
lc_messages = en_US
saltare-external-bloccaggio
#
# Invece di saltare la rete, il valore predefinito è ora solo per l'ascolto
# localhost che è più compatibile e non meno sicuro.
bind-address = 127.0.0.1
#
# * Ritocchi
#
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
#
# Questo sostituisce lo script di avvio e controlla le tabelle MyISAM se necessario
# la prima volta che vengono toccati. In caso di errore, copia e prova a riparare.
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
#
# * Configurazione cache query
#
# Cache solo minuscoli set di risultati, in modo che possiamo adattarci maggiormente alla cache delle query.
query_cache_limit = 128K
query_cache_size = 64M
# per impostazioni più intense di scrittura, impostare su RICHIESTA o DISATTIVATO
#query_cache_type = DOMANDA
#
# * Registrazione e replica
#
# Entrambe le posizioni vengono ruotate dal cronjob.
# Tenere presente che questo tipo di registro è un killer delle prestazioni.
# A partire da 5.1 è possibile abilitare il registro in fase di esecuzione!
#general_log_file = /var/log/mysql/mysql.log
#general_log = 1
#
# La registrazione degli errori va su syslog a causa di /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
#
# vogliamo conoscere errori di rete e simili
log_warnings = 2
#
# Abilitare il registro delle query lente per visualizzare le query con una durata particolarmente lunga
#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-query-non-uso-indici
#log_slow_admin_statements
#
# È possibile utilizzare quanto segue per riprodurre facilmente i registri di backup o per la replica.
# nota: se si sta configurando uno slave di replica, consultare README.Debian about
# altre impostazioni che potresti dover modificare.
# 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
# non favoloso per le prestazioni, ma più sicuro
#sync_binlog = 1
expire_logs_days = 10
max_binlog_size = 100M
# schiavi
#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
#sola lettura
#
# Se le applicazioni lo supportano, questo sql_mode più rigoroso ne impedisce alcune
# errori come l'inserimento di date non valide ecc.
#sql_mode = NO_ENGINE_SUBSTITUTION, TRADIZIONALE
#
# * InnoDB
#
# InnoDB è abilitato di default con un file di dati da 10 MB in / var / lib / mysql /.
# Leggi il manuale per ulteriori opzioni relative a InnoDB. Ci sono molti!
default_storage_engine = InnoDB
# non puoi semplicemente modificare le dimensioni del file di registro, richiede una procedura speciale
#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
#
# * Caratteristiche di sicurezza
#
# Leggi anche il manuale, se vuoi chroot!
# chroot = / var / lib / mysql /
#
# Per generare certificati SSL, consiglio la GUI di OpenSSL "tinyca".
#
# ssl-ca = / etc / mysql / cacert.pem
# ssl-cert = / etc / mysql / server-cert.pem
# ssl-key = / etc / mysql / server-key.pem



[Mysqldump]
Presto
quote-nomi
max_allowed_packet = 16M

[Mysql]
# no-auto-rehash # avvio più veloce di mysql ma nessun completamento della scheda

[Isamchk]
key_buffer = 16M

#
# * IMPORTANTE: impostazioni aggiuntive che possono sovrascrivere quelle da questo file!
# I file devono terminare con '.cnf', altrimenti verranno ignorati.
#
! includedir /etc/mysql/conf.d/

E il contenuto delle variabili inno:

MariaDB [(nessuno)]> MOSTRA VARIABILI COME 'inno%';
+ ------------------------------------------- + ----- ------------------- +
| Nome variabile | Valore |
+ ------------------------------------------- + ----- ------------------- +
| 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 | tutto |
| 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 | affermare |
| 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 | Antilope |
| innodb_file_format_check | ON |
| innodb_file_format_max | Antilope |
| 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 righe in set (0,02 sec)

Il numero di core della macchina è 8, è a

Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz come di /proc/cpuinfo

Un'ultima nota: ho eseguito le query con gli indici suggeriti da RolandoMYSQLDBA e le query hanno richiesto circa 11-20 secondi ciascuna. Voglio sottolineare che per me è cruciale (questa è la tabella principale di una bacheca) che la prima query su un threadid ritorna in meno di un secondo, poiché ci sono più di 60.000 thread e google-bot strisciano costantemente questi fili.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Paul White dice GoFundMonica

Risposte:


24

LA TUA DOMANDA

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

A prima vista, la query dovrebbe toccare solo l'1,1597% (62510 su 5390146) della tabella. Dovrebbe essere veloce data la distribuzione chiave di threadid 51506.

CONTROLLO DI REALTÀ

Indipendentemente dalla versione di MySQL (Oracle, Percona, MariaDB) utilizzata, nessuna di esse può combattere contro un nemico che tutti hanno in comune: l'architettura InnoDB.

Architettura di InnoDB

INDICE CLUSTERATO

Si prega di tenere presente che ogni voce threadid ha una chiave primaria allegata. Ciò significa che quando si legge dall'indice, deve eseguire una ricerca della chiave primaria all'interno di ClusteredIndex (internamente denominato gen_clust_index) . In ClusteredIndex, ogni pagina InnoDB contiene sia dati che informazioni sull'indice PRIMARY KEY. Vedi il mio post Best of MyISAM e InnoDB per maggiori informazioni.

INDICI RIDONDANTI

Hai un sacco di disordine nella tabella perché alcuni indici hanno le stesse colonne iniziali. MySQL e InnoDB devono navigare nel disordine dell'indice per raggiungere i nodi BTREE necessari. È necessario ridurre il disordine eseguendo quanto segue:

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`)
;

Perché eliminare questi indici?

  • I primi tre indici iniziano con threadid
  • threadid_2e threadid_visible_datelineinizia con le stesse tre colonne
  • threadid_visible_dateline non ha bisogno di postid poiché è il PRIMARY KEY ed è incorporato

CACHING DEL BUFFER

Il pool di buffer InnoDB memorizza nella cache i dati e le pagine dell'indice. MyISAM memorizza solo nella cache le pagine dell'indice.

Solo in quest'area, MyISAM non perde tempo nella memorizzazione dei dati nella cache. Questo perché non è progettato per memorizzare nella cache i dati. InnoDB memorizza nella cache ogni pagina di dati e pagina di indice (e sua nonna) che tocca. Se il pool di buffer InnoDB è troppo piccolo, è possibile memorizzare nella cache le pagine, invalidare le pagine e rimuovere le pagine in un'unica query.

LAYOUT DELLA TABELLA

Potresti radere un po 'di spazio dalla riga considerando importthreadide importpostid. Li hai come GRANDI. Occupano 16 byte in ClusteredIndex per riga.

Dovresti eseguire questo

SELECT importthreadid,importpostid FROM newbb_innopost PROCEDURE ANALYSE();

Ciò consiglierà quali tipi di dati dovrebbero essere queste colonne per il set di dati specificato.

CONCLUSIONE

MyISAM ha molto meno a che fare con InnoDB, specialmente nell'area della cache.

Mentre hai rivelato la quantità di RAM ( 32GB) e la versione di MySQL ( Server version: 10.0.12-MariaDB-1~trusty-wsrep-log mariadb.org binary distribution, wsrep_25.10.r4002), ci sono ancora altri pezzi di questo puzzle che non hai rivelato

  • Le impostazioni di InnoDB
  • Il numero di core
  • Altre impostazioni da my.cnf

Se puoi aggiungere queste cose alla domanda, posso approfondire ulteriormente.

AGGIORNAMENTO 2014-08-28 11:27 EDT

Dovresti aumentare il threading

innodb_read_io_threads = 64
innodb_write_io_threads = 16
innodb_log_buffer_size = 256M

Prenderei in considerazione la disabilitazione della cache delle query (vedi il mio post recente Perché query_cache_type è disabilitato di default a partire da MySQL 5.6? )

query_cache_size = 0

Vorrei preservare il pool di buffer

innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1

Aumenta i thread di eliminazione (se esegui DML su più tabelle)

innodb_purge_threads = 4

PROVACI !!!


So che InnoDB dovrebbe essere più lento in un test di velocità pura, ma fino a questo punto? Ho letto che il team MySQL ha lavorato duramente per colmare questa lacuna. Abbiamo ancora a che fare con un aumento di ~ 100 volte! Domanda: stai dicendo che le query di questa natura sarebbero meglio servite con un indice B-tree "diretto" non cluster (cioè senza avere i dati PK inclusi)? In tal caso, perché questo / non è stato / non è stato implementato? La funzionalità richiesta dall'OP non è sicuramente un caso d'uso marginale.
Vérace,

Puoi aggiungere un link alla versione full size di quella foto? Alcune parti sono difficili da leggere :-)
acquoso

@RolandMySQLDBA grazie per l'informazione - Spero non stia suggerendo che un rallentamento di 100x sia "normale" per InnoDB ... Potrei vivere con 2x o 3x, ma 100x è semplicemente troppo. Come richiesto, ho aggiunto le informazioni mancanti alla mia domanda :) Grazie per le spiegazioni finora! Numero di core della macchina è 8.
jollyroger

2
@watery Ecco l'immagine a dimensioni
intere

1
Grazie mille per il tuo aiuto @RolandoMySQLDBA, sfortunatamente anche queste ultime modifiche non sono state utili e InnoDB impiega circa 11-20 secondi per essere completato. Ho provato qualcosa in base alla tua risposta: eliminare tutti gli indici e creare un indice di copertura. Questo ha aiutato molto. Senza la tua spiegazione degli indici non avrei trovato questa soluzione.
Verificherò la

7

@RolandMySQLDBA ha dato il giusto suggerimento per rispondere alla domanda. Il problema sembra risiedere nella query e che affinché i risultati vengano restituiti, ciascuno di questi campi deve essere letto (in qualche modo dal database).

Ho lasciato cadere tutti gli indici tranne il PRIMARY KEY, e ho inserito questo nuovo indice:

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

Questo link spiega cosa succede qui ( indice di copertura ): I campi interrogati della query che sonopostid,attach ora possono essere estratti dalla chiave stessa. Ciò consente di risparmiare controllando i dati reali e usando l'I / O sul disco rigido.

Tutte le query ora vengono eseguite con 0,00 secondi .. :)

Grazie mille per il tuo aiuto.

Modifica : il vero problema di fondo non è stato risolto, l'ho solo aggirato con questa tecnica. InnoDB ha bisogno di alcune riparazioni serie in questo settore.


sto affrontando lo stesso problema. la query myisma richiede 0,01 secondi mentre innodb richiede 60 secondi, provando i tuoi suggerimenti.
AMB

@AMB - 0,01s puzza di cache delle query; volta di nuovo con SQL_NO_CACHE.
Rick James,

0

In base sia alla query che alla tabella sembra che tu stia selezionando i dati da una tabella delle serie temporali. Come tale, può darsi che il tempo della query sia lento perché si sta inserendo contemporaneamente?

Se queste due cose sono vere, allora potrei suggerire di considerare ScaleDB come alternativa? Sarai ancora su MariaDB, solo (forse) un motore più appropriato.

http://www.scaledb.com - Home page http://www.scaledb.com/download-form.php - il nostro prodotto


2
È necessario aggiungere che l'edizione principale non è gratuita.
ypercubeᵀᴹ

0

Entrambi i motori eseguiranno la query molto più velocemente con

INDEX(threadid, attach, postid)

Questo perché sarà un indice "coprente" e funzionerà praticamente allo stesso modo (usando l'indice BTree).

Inoltre, dirò che questo non è possibile per entrambi i motori su un server "freddo":

62510 rows in set (0.13 sec)

Si prega di utilizzare SQL_NO_CACHEogni volta che si eseguono i tempi - non vogliamo che la cache delle query inquini le conclusioni.

Un altro approccio rapido (senza registrazione della cache di I / O):

Usa InnoDB e cambia da PRIMARY KEY (postid)a

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

Il motivo è che questo farà sì che tutte le righe pertinenti siano adiacenti, richiedendo quindi meno I / O, ecc. INDEX(postid)È per essere AUTO_INCREMENTfelici. Avvertenza: questo si confonde con tutte le chiavi secondarie: alcune saranno più veloci, altre più lente.


0

Sebbene non sia direttamente applicabile a @jollyroger perché ha già l'impostazione corretta, ma ho ottenuto un notevole miglioramento cambiando il innodb_buffer_pool_size70% della mia RAM, come spiegato in Perché myisam è più lento di Innodb

Il primo è MyISAMstato lento, ma ok. Quindi ha InnoDBreso le cose peggiori, simili al 100x più lento in questa domanda e dopo aver modificato l'impostazione è InnoDBdiventato 10 volte più veloce di allora MyISAM.

La mia impostazione predefinita era su 8 MB, che è molto poco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.