Tengo un problema bastante molesto. Quiero usar INNODB como mi motor de base de datos principal y renunciar a MyISAM ya que necesito el primero para usar galera-cluster para la redundancia.
Copié (la descripción sigue) la newbb_post
tabla a una nueva tabla llamada newbb_innopost
y la cambié a InnoDB. Las tablas actualmente contienen 5,390,146
entradas cada una.
Al ejecutar estas selecciones en una base de datos recién iniciada (¡por lo que no hay almacenamiento en caché en este momento!), La base de datos produce los siguientes resultados (omitiendo la salida completa, tenga en cuenta que ni siquiera le pido a la base de datos que ordene los resultados):
SELECCIONE post.postid, post.attach FROM newbb_post COMO post DONDE post.threadid = 51506; . . El | 5401593 | 0 | El | 5401634 | 0 | + --------- + -------- + 62510 filas en conjunto (0,13 segundos)
SELECCIONE post.postid, post.attach FROM newbb_innopost COMO post DONDE post.threadid = 51506; . . El | 5397410 | 0 | El | 5397883 | 0 | + --------- + -------- + 62510 filas en conjunto (1 min 22.19 seg)
0.13 segundos a 86.19 segundos (!)
Me pregunto por qué está sucediendo esto. Leí algunas respuestas aquí en Stackexchange que involucran a InnoDB y algunas sugieren aumentar el innodb_buffer_pool
tamaño al 80% de la RAM instalada. Esto no resolverá el problema, que la consulta inicial a una ID en particular tomará al menos 50 veces más tiempo y detendrá todo el servidor web, poniendo en cola las conexiones y consultas para la base de datos. Posteriormente, el caché / búfer podría iniciarse, pero hay más de 100.000 subprocesos en esta base de datos, por lo que es muy probable que el caché nunca contenga todas las consultas relevantes para ser atendidas.
Las consultas anteriores son simples (sin combinaciones) y se utilizan todas las claves:
EXPLIQUE SELECT post.postid, post.attach FROM newbb_innopost COMO post DONDE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + El | id | select_type | mesa | tipo | posibles_claves | clave | key_len | ref | filas | Extra | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + El | 1 | SIMPLE | post | ref | threadid, threadid_2, threadid_visible_dateline | threadid | 4 | const | 120144 | El | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
Esta es la tabla 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', `pagetext` mediumtext, `allowmilie` smallint (6) NO NULL DEFAULT '0', `showsignature` smallint (6) NO NULL DEFAULT '0', `ipaddress` varchar (15) NO NULL DEFAULT '', `iconid` smallint (5) unsigned NOT NULL DEFAULT '0', `visible` smallint (6) NO 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) NO NULL DEFAULT '0', `importpostid` bigint (20) NO NULL DEFAULT '0', `convertido_2_utf8` int (11) NO NULL, `htmlstate` enum ('off', 'on', 'on_nl2br') NOT NULL DEFAULT 'on_nl2br', CLAVE PRIMARIA (`postid`), KEY `threadid` (` threadid`, `userid`), TECLA `importpost_index` (` importpostid`), KEY `dateline` (` dateline`), KEY `threadid_2` (` threadid`, `visible`,` dateline`), TECLA `convertido_2_utf8` (` convertido_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 CHARSET POR DEFECTO = latin1
y esta es la tabla InnoDB (es exactamente la misma):
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', `pagetext` mediumtext, `allowmilie` smallint (6) NO NULL DEFAULT '0', `showsignature` smallint (6) NO NULL DEFAULT '0', `ipaddress` varchar (15) NO NULL DEFAULT '', `iconid` smallint (5) unsigned NOT NULL DEFAULT '0', `visible` smallint (6) NO 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) NO NULL DEFAULT '0', `importpostid` bigint (20) NO NULL DEFAULT '0', `convertido_2_utf8` int (11) NO NULL, `htmlstate` enum ('off', 'on', 'on_nl2br') NOT NULL DEFAULT 'on_nl2br', CLAVE PRIMARIA (`postid`), KEY `threadid` (` threadid`, `userid`), TECLA `importpost_index` (` importpostid`), KEY `dateline` (` dateline`), KEY `threadid_2` (` threadid`, `visible`,` dateline`), TECLA `convertido_2_utf8` (` convertido_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 DEFAULT CHARSET = latin1
Servidor, con 32 GB de RAM:
versión del servidor: 10.0.12-MariaDB-1 ~ confianza wsrep-log-mariadb.org distribución binaria, wsrep_25.10.r4002
Si necesita todas las variables de ajuste innodb_, puedo adjuntar que a este mensaje.
Actualizar:
Descarté TODOS los índices aparte del índice primario, luego el resultado se veía así:
. . El | 5402697 | 0 | El | 5402759 | 0 | + --------- + -------- + 62510 filas en conjunto (29.74 segundos)
EXPLIQUE SELECT post.postid, post.attach FROM newbb_innopost COMO post DONDE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + El | id | select_type | mesa | tipo | posibles_claves | clave | key_len | ref | filas | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + El | 1 | SIMPLE | post | TODOS | NULL | NULL | NULL | NULL | 5909836 | Usando donde | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + 1 fila en conjunto (0.00 seg)
Después de esto, acabo de agregar un índice a la mezcla, threadid, los resultados fueron los siguientes:
. . El | 5402697 | 0 | El | 5402759 | 0 | + --------- + -------- + 62510 filas en conjunto (11.58 segundos)
EXPLIQUE SELECT post.postid, post.attach FROM newbb_innopost COMO post DONDE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + El | id | select_type | mesa | tipo | posibles_claves | clave | key_len | ref | filas | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + El | 1 | SIMPLE | post | ref | threadid | threadid | 4 | const | 124622 | El | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + 1 fila en conjunto (0.00 seg)
Es extraño, que sin índices relevantes, la exploración completa solo tomó 29 segundos en comparación con los 88 segundos usando índices (!).
Con solo un índice perfectamente adaptado, todavía tarda 11 segundos en completarse, aún demasiado lento para cualquier uso en el mundo real.
Actualización 2:
Configuré MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) en otro servidor con exactamente la misma configuración de hardware y exactamente la misma base de datos / tablas.
Los resultados son casi los mismos, primero la tabla MyISAM:
. . El | 5401593 | 0 | El | 5401634 | 0 | + --------- + -------- + 62510 filas en conjunto (0.14 seg)
Y este es el resultado de la tabla InnoDB
. . El | 5397410 | 0 | El | 5397883 | 0 | + --------- + -------- + 62510 filas en conjunto (1 min 17.63 seg)
ACTUALIZACIÓN 3: los contenidos de my.cnf
# MariaDB archivo de configuración del servidor de base de datos. # # # Puede copiar este archivo a uno de: # - "/etc/mysql/my.cnf" para establecer opciones globales, # - "~ / .my.cnf" para configurar las opciones específicas del usuario. # # # Uno puede usar todas las opciones largas que admite el programa. # Ejecute el programa con --help para obtener una lista de opciones disponibles y con # --print-defaults para ver cuál realmente entendería y usaría. # # # Para explicaciones ver # http://dev.mysql.com/doc/mysql/en/server-system-variables.html # Esto se pasará a todos los clientes mysql # Se ha informado que las contraseñas se deben incluir con marcas / comillas # especialmente si contienen caracteres "#" ... # Recuerde editar /etc/mysql/debian.cnf cuando cambie la ubicación del socket. [cliente] puerto = 3306 socket = /var/run/mysqld/mysqld.sock # Aquí hay entradas para algunos programas específicos # Los siguientes valores suponen que tiene al menos 32M de ram # Esto se conocía formalmente como [safe_mysqld]. Ambas versiones están actualmente analizadas. [mysqld_safe] socket = /var/run/mysqld/mysqld.sock bonito = 0 [mysqld] # # # * Ajustes básicos # # usuario = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock puerto = 3306 basedir = / usr datadir = / var / lib / mysql tmpdir = / tmp lc_messages_dir = / usr / share / mysql lc_messages = en_US saltar-bloqueo externo # # # En lugar de omitir redes, el valor predeterminado ahora es escuchar solo en # localhost, que es más compatible y no es menos seguro. dirección-enlace = 127.0.0.1 # # # * Sintonia FINA # # 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 # # # Esto reemplaza el script de inicio y comprueba las tablas MyISAM si es necesario # la primera vez que se tocan. En caso de error, haga una copia e intente una reparación. 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 # # # * Configuración de la caché de consultas # # # Caché solo pequeños conjuntos de resultados, por lo que podemos caber más en el caché de consultas. query_cache_limit = 128K query_cache_size = 64M # para configuraciones más intensivas de escritura, configure en DEMAND u OFF #query_cache_type = DEMANDA # # # * Registro y replicación # # # Ambas ubicaciones se rotan por el cronjob. # Tenga en cuenta que este tipo de registro es un asesino de rendimiento. # ¡A partir de 5.1 puede habilitar el registro en tiempo de ejecución! #general_log_file = /var/log/mysql/mysql.log #general_log = 1 # # # El registro de errores va a syslog debido a /etc/mysql/conf.d/mysqld_safe_syslog.cnf. # # # queremos saber acerca de los errores de red y tales log_warnings = 2 # # # Habilite el registro lento de consultas para ver consultas con una duración especialmente larga #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 # # # Lo siguiente se puede usar como registros de respaldo fáciles de reproducir o para replicar. # nota: si está configurando un esclavo de replicación, consulte README.Debian acerca de # otras configuraciones que puede necesitar cambiar. # id-servidor = 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 # no es fabuloso para el rendimiento, pero es más seguro #sync_binlog = 1 expire_logs_days = 10 max_binlog_size = 100M # esclavos #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 #solo lectura # # # Si las aplicaciones lo admiten, este sql_mode más estricto evita algunos # errores como insertar fechas inválidas, etc. #sql_mode = NO_ENGINE_SUBSTITUTION, TRADITIONAL # # # * InnoDB # # # InnoDB está habilitado de forma predeterminada con un archivo de datos de 10 MB en / var / lib / mysql /. # Lea el manual para más opciones relacionadas con InnoDB. ¡Hay muchos! default_storage_engine = InnoDB # no puede simplemente cambiar el tamaño del archivo de registro, requiere un procedimiento 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 # # # * Características de seguridad # # # ¡Lea también el manual si quiere chroot! # chroot = / var / lib / mysql / # # # Para generar certificados SSL, recomiendo la GUI de 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 nombres de comillas max_allowed_packet = 16M [mysql] # no-auto-rehash # inicio más rápido de mysql pero sin completar la pestaña [isamchk] key_buffer = 16M # # # * IMPORTANTE: ¡Configuraciones adicionales que pueden anular las de este archivo! # Los archivos deben terminar con '.cnf', de lo contrario serán ignorados. # # ! includedir /etc/mysql/conf.d/
Y el contenido de las variables inno:
MariaDB [(ninguno)]> MOSTRAR VARIABLES COMO 'inno%'; + ------------------------------------------- + ----- ------------------- + El | Nombre_variable | Valor | + ------------------------------------------- + ----- ------------------- + El | innodb_adaptive_flushing | ON | El | innodb_adaptive_flushing_lwm | 10 | El | innodb_adaptive_hash_index | ON | El | innodb_adaptive_hash_index_partitions | 1 | El | innodb_adaptive_max_sleep_delay | 150000 | El | innodb_additional_mem_pool_size | 8388608 | El | innodb_api_bk_commit_interval | 5 | El | innodb_api_disable_rowlock | OFF | El | innodb_api_enable_binlog | OFF | El | innodb_api_enable_mdl | OFF | El | innodb_api_trx_level | 0 | El | innodb_autoextend_increment | 64 El | innodb_autoinc_lock_mode | 1 | El | innodb_buffer_pool_dump_at_shutdown | OFF | El | innodb_buffer_pool_dump_now | OFF | El | innodb_buffer_pool_filename | ib_buffer_pool | El | innodb_buffer_pool_instances | 8 | El | innodb_buffer_pool_load_abort | OFF | El | innodb_buffer_pool_load_at_startup | OFF | El | innodb_buffer_pool_load_now | OFF | El | innodb_buffer_pool_populate | OFF | El | innodb_buffer_pool_size | 21474836480 | El | innodb_change_buffer_max_size | 25 El | innodb_change_buffering | todos | El | innodb_checksum_algorithm | innodb | El | innodb_checksums | ON | El | innodb_cleaner_lsn_age_factor | high_checkpoint | El | innodb_cmp_per_index_enabled | OFF | El | innodb_commit_concurrency | 0 | El | innodb_compression_failure_threshold_pct | 5 | El | innodb_compression_level | 6 | El | innodb_compression_pad_pct_max | 50 El | innodb_concurrency_tickets | 5000 | El | innodb_corrupt_table_action | afirmar | El | innodb_data_file_path | ibdata1: 12M: autoextend | El | innodb_data_home_dir | El | El | innodb_disable_sort_file_cache | OFF | El | innodb_doublewrite | ON | El | innodb_empty_free_list_algorithm | retroceso | El | innodb_fake_changes | OFF | El | innodb_fast_shutdown | 1 | El | innodb_file_format | Antílope | El | innodb_file_format_check | ON | El | innodb_file_format_max | Antílope | El | innodb_file_per_table | ON | El | innodb_flush_log_at_timeout | 1 | El | innodb_flush_log_at_trx_commit | 1 | El | innodb_flush_method | O_DIRECT | El | innodb_flush_neighbours | 1 | El | innodb_flushing_avg_loops | 30 El | innodb_force_load_corrupted | OFF | El | innodb_force_recovery | 0 | El | innodb_foreground_preflush | exponencial_backoff | El | innodb_ft_aux_table | El | El | innodb_ft_cache_size | 8000000 | El | innodb_ft_enable_diag_print | OFF | El | innodb_ft_enable_stopword | ON | El | innodb_ft_max_token_size | 84 El | innodb_ft_min_token_size | 3 | El | innodb_ft_num_word_optimize | 2000 | El | innodb_ft_result_cache_limit | 2000000000 | El | innodb_ft_server_stopword_table | El | El | innodb_ft_sort_pll_degree | 2 | El | innodb_ft_total_cache_size | 640000000 | El | innodb_ft_user_stopword_table | El | El | innodb_io_capacity | 400 | El | innodb_io_capacity_max | 2000 | El | innodb_kill_idle_transaction | 0 | El | innodb_large_prefix | OFF | El | innodb_lock_wait_timeout | 50 El | innodb_locking_fake_changes | ON | El | innodb_locks_unsafe_for_binlog | OFF | El | innodb_log_arch_dir | ./ | El | innodb_log_arch_expire_sec | 0 | El | innodb_log_archive | OFF | El | innodb_log_block_size | 512 El | innodb_log_buffer_size | 8388608 | El | innodb_log_checksum_algorithm | innodb | El | innodb_log_compressed_pages | ON | El | innodb_log_file_size | 50331648 | El | innodb_log_files_in_group | 2 | El | innodb_log_group_home_dir | ./ | El | innodb_lru_scan_depth | 1024 | El | innodb_max_bitmap_file_size | 104857600 | El | innodb_max_changed_pages | 1000000 | El | innodb_max_dirty_pages_pct | 75 | El | innodb_max_dirty_pages_pct_lwm | 0 | El | innodb_max_purge_lag | 0 | El | innodb_max_purge_lag_delay | 0 | El | innodb_mirrored_log_groups | 1 | El | innodb_monitor_disable | El | El | innodb_monitor_enable | El | El | innodb_monitor_reset | El | El | innodb_monitor_reset_all | El | El | innodb_old_blocks_pct | 37 | El | innodb_old_blocks_time | 1000 | El | innodb_online_alter_log_max_size | 134217728 | El | innodb_open_files | 400 | El | innodb_optimize_fulltext_only | OFF | El | innodb_page_size | 16384 | El | innodb_print_all_deadlocks | OFF | El | innodb_purge_batch_size | 300 El | innodb_purge_threads | 1 | El | innodb_random_read_ahead | OFF | El | innodb_read_ahead_threshold | 56 El | 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 rows in set (0.02 sec)
The number of cores of the machine is 8, it's a
Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz
as of /proc/cpuinfo
One last note: Ran the queries with the indexes suggested by RolandoMYSQLDBA, and the queries took about 11-20s each. I do want to point out that it is crucial for me (this is the main table of a bulletin board) that the first query about a threadid returns in less than a second, as there are more than 60.000 threads and google-bots constantly crawl these threads.