J'ai un problème assez ennuyant. Je souhaite utiliser INNODB comme moteur de base de données principal et abandonner MyISAM, car j’ai besoin du premier pour utiliser galera-cluster à des fins de redondance.
J'ai copié (la description suit) la newbb_post
table dans une nouvelle table appelée newbb_innopost
et l' ai modifiée en InnoDB. Les tables contiennent actuellement des 5,390,146
entrées chacune.
L'exécution de ces sélections sur une base de données fraîchement démarrée (afin qu'aucune mise en cache ne soit impliquée à ce stade!), La base de données donne les résultats suivants (en omettant la sortie complète, veuillez noter que je ne demande même pas à la base de données de trier les résultats):
SELECT post.postid, post.attach FROM newbb_post AS post WHERE post.threadid = 51506; . . | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 62510 lignes dans un ensemble (0.13 sec)
SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; . . | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 62510 lignes par séries (1 min 22.19 sec)
0,13 seconde à 86,19 secondes (!)
Je me demande pourquoi cela se produit. J'ai lu quelques réponses ici sur Stackexchange impliquant InnoDB et certaines suggèrent d'augmenter la innodb_buffer_pool
taille à 80% de la RAM installée. Cela ne résoudra pas le problème suivant: la requête initiale à un ID particulier prendra au moins 50 fois plus longtemps et bloquera la totalité de la recherche Web, mettant en file d'attente les connexions et les requêtes pour la base de données. Ensuite, le cache / tampon peut démarrer, mais il y a plus de 100 000 threads dans cette base de données. Il est donc très probable que le cache ne contiendra jamais toutes les requêtes pertinentes à traiter.
Les requêtes ci-dessus sont simples (pas de jointures) et toutes les clés sont utilisées:
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | id | select_type | table | type | possible_keys | clé | key_len | ref | rangées | Extra | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | 1 | SIMPLE | post | ref | threadid, threadid_2, threadid_visible_dateline | threadid | 4 | const | 120144 | | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
C'est la table MyISAM:
CREATE TABLE `newbb_post` ( `postid` int (10) non signé NOT NULL AUTO_INCREMENT, `threadid` int (10) non signé NOT NULL DEFAULT '0', `parentid` int (10) non signé NOT NULL DEFAULT '0', `username` varchar (100) NOT NULL DEFAULT '', `userid` int (10) non signé NOT NULL DEFAULT '0', `title` varchar (250) NOT NULL DEFAULT '', `dateline` int (10) non signé NOT NULL DEFAULT '0', `pagetext` mediumtext, `allowmilie` smallint (6) PAS NULL DEFAULT '0', `showsignature` smallint (6) NOT NULL DEFAULT '0', `ipaddress` varchar (15) NOT NULL DEFAULT '', `iconid` smallint (5) non signé NOT NULL DEFAULT '0', `visible` smallint (6) NOT NULL DEFAULT '0', `attach` smallint (5) non signé NOT NULL DEFAULT '0', `infraction` smallint (5) non signé NOT NULL DEFAULT '0', `reportthreadid` int (10) non signé 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') NOT NULL DEFAULT 'on_nl2br', PRIMARY KEY (`postid`), KEY `threadid` (` threadid`, `userid`), KEY `importpost_index` (` importpostid`), KEY `dateline` (` dateline`), KEY `threadid_2` (` threadid`, `visible`,` dateline`), CLÉ `converti_2_utf8` (` converti2_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 CHARGEMENT PAR DEFAUT = latin1
et voici la table InnoDB (c'est exactement la même chose):
CREATE TABLE `newbb_innopost` ( `postid` int (10) non signé NOT NULL AUTO_INCREMENT, `threadid` int (10) non signé NOT NULL DEFAULT '0', `parentid` int (10) non signé NOT NULL DEFAULT '0', `username` varchar (100) NOT NULL DEFAULT '', `userid` int (10) non signé NOT NULL DEFAULT '0', `title` varchar (250) NOT NULL DEFAULT '', `dateline` int (10) non signé NOT NULL DEFAULT '0', `pagetext` mediumtext, `allowmilie` smallint (6) PAS NULL DEFAULT '0', `showsignature` smallint (6) NOT NULL DEFAULT '0', `ipaddress` varchar (15) NOT NULL DEFAULT '', `iconid` smallint (5) non signé NOT NULL DEFAULT '0', `visible` smallint (6) NOT NULL DEFAULT '0', `attach` smallint (5) non signé NOT NULL DEFAULT '0', `infraction` smallint (5) non signé NOT NULL DEFAULT '0', `reportthreadid` int (10) non signé 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') NOT NULL DEFAULT 'on_nl2br', PRIMARY KEY (`postid`), KEY `threadid` (` threadid`, `userid`), KEY `importpost_index` (` importpostid`), KEY `dateline` (` dateline`), KEY `threadid_2` (` threadid`, `visible`,` dateline`), CLÉ `converti_2_utf8` (` converti2_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 CHARGEMENT PAR DEFAUT = latin1
Serveur, avec 32 Go de RAM:
Version du serveur: 10.0.12-MariaDB-1 ~ trusty-wsrep-log distribution binaire de mariadb.org, wsrep_25.10.r4002
Si vous avez besoin de tous les paramètres innodb_ variables, je peux l’attacher à cet article.
Mise à jour:
J'ai abandonné TOUS les index en dehors de l'index primaire. Après, le résultat ressemblait à ceci:
. . | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 62510 lignes dans la série (29.74 sec)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | id | select_type | table | type | possible_keys | clé | key_len | ref | rangées | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | 1 | SIMPLE | post | TOUS | NULL | NULL | NULL | NULL | 5909836 | Utiliser où | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + 1 ligne dans le set (0.00 sec)
Après cela, je viens d'ajouter un index au mélange, threadid, les résultats sont les suivants:
. . | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 62510 lignes dans le jeu (11.58 sec)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | id | select_type | table | type | possible_keys | clé | key_len | ref | rangées | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | 1 | SIMPLE | post | ref | threadid | threadid | 4 | const | 124622 | | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + 1 ligne dans le set (0.00 sec)
Il est étrange que, sans index pertinents, l’analyse complète ne prenne que 29 secondes, contre 88 secondes avec les index (!).
Avec un seul index parfaitement adapté, il faut encore 11 secondes - encore beaucoup trop lentement pour une utilisation dans le monde réel.
Mise à jour 2:
J'ai installé MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) sur un autre serveur avec exactement la même configuration matérielle et exactement la même base de données / tables.
Les résultats sont presque les mêmes, d’abord le tableau MyISAM:
. . | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 62510 lignes dans un ensemble (0,14 sec)
Et ceci est le résultat de la table InnoDB
. . | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 62510 lignes par série (1 min 17.63 sec)
UPDATE 3: le contenu de my.cnf
# Fichier de configuration du serveur de base de données MariaDB. # # Vous pouvez copier ce fichier dans l’un des fichiers suivants: # - "/etc/mysql/my.cnf" pour définir les options globales, # - "~ / .my.cnf" pour définir les options spécifiques à l'utilisateur. # # On peut utiliser toutes les options longues prises en charge par le programme. # Exécutez le programme avec --help pour obtenir une liste des options disponibles et avec # --print-defaults pour voir ce qu'il comprend et utilise réellement. # # Pour des explications voir # http://dev.mysql.com/doc/mysql/en/server-system-variables.html # Ceci sera transmis à tous les clients mysql # Il a été rapporté que les mots de passe devraient être entourés de ticks / guillemets # surtout si elles contiennent "#" des caractères ... # N'oubliez pas de modifier /etc/mysql/debian.cnf lors de la modification de l'emplacement du socket. [client] port = 3306 socket = /var/run/mysqld/mysqld.sock # Voici les entrées pour certains programmes spécifiques # Les valeurs suivantes supposent que vous avez au moins 32 millions de RAM # Ceci était officiellement connu sous le nom [safe_mysqld]. Les deux versions sont actuellement analysées. [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # # * Paramètres de base # utilisateur = 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 = en_US sauter-verrouillage externe # # Au lieu de sauter le réseau, la valeur par défaut est maintenant d'écouter uniquement # localhost qui est plus compatible et n'est pas moins sécurisé. bind-address = 127.0.0.1 # # * Réglage fin # 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 # # Ceci remplace le script de démarrage et vérifie les tables MyISAM si nécessaire # la première fois qu'ils sont touchés. En cas d'erreur, faites une copie et essayez une réparation. myisam_recover = SAUVEGARDE 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 # # * Configuration du cache de requêtes # # Cache seulement les jeux de résultats minuscules, ainsi nous pouvons en insérer davantage dans le cache de requêtes. query_cache_limit = 128K query_cache_size = 64M # pour des configurations plus intensives en écriture, réglez sur DEMAND ou OFF #query_cache_type = DEMAND # # * Journalisation et réplication # # Les deux emplacements sont tournés par le cronjob. # Sachez que ce type de journal est un facteur de perte de performances. # À partir de la version 5.1, vous pouvez activer le journal au moment de l’exécution! #general_log_file = /var/log/mysql/mysql.log #general_log = 1 # # La journalisation des erreurs va à syslog en raison de /etc/mysql/conf.d/mysqld_safe_syslog.cnf. # # nous voulons connaître les erreurs de réseau et autres log_warnings = 2 # # Activer le journal de requête lent pour voir les requêtes avec une durée particulièrement longue #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 # # Les éléments suivants peuvent être utilisés pour relire facilement les journaux de sauvegarde ou pour la réplication. # remarque: si vous configurez un esclave de réplication, voir README.Debian à propos de # autres paramètres que vous devrez peut-être modifier. # id-serveur = 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 # pas fabuleux pour la performance, mais plus sûr #sync_binlog = 1 expire_logs_days = 10 max_binlog_size = 100M # des esclaves #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 #lecture seulement # # Si les applications le supportent, ce sql_mode plus strict empêche certaines # erreurs comme l'insertion de dates invalides, etc. #sql_mode = NO_ENGINE_SUBSTITUTION, TRADITIONAL # # * InnoDB # # InnoDB est activé par défaut avec un fichier de données de 10 Mo dans / var / lib / mysql /. # Lisez le manuel pour plus d'options liées à InnoDB. Il y a beaucoup de! default_storage_engine = InnoDB # vous ne pouvez pas simplement changer la taille du fichier journal, nécessite une procédure spéciale #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 # # * Fonctions de sécurité # # Lisez aussi le manuel, si vous voulez chroot! # chroot = / var / lib / mysql / # # Pour générer des certificats SSL, je recommande l'interface graphique OpenSSL "tinyca". # # ssl-ca = / etc / mysql / cacert.pem # ssl-cert = / etc / mysql / server-cert.pem # ssl-key = / etc / mysql / server-key.pem [mysqldump] rapide noms de citation max_allowed_packet = 16M [mysql] # no-auto-rehash # démarrage plus rapide de mysql mais pas de complétion des onglets [isamchk] key_buffer = 16M # # * IMPORTANT: paramètres supplémentaires pouvant remplacer ceux de ce fichier! # Les fichiers doivent se terminer par '.cnf', sinon ils seront ignorés. # ! includedir /etc/mysql/conf.d/
Et le contenu des variables inno:
MariaDB [(none)]> AFFICHER LES VARIABLES LIKE 'inno%'; + ------------------------------------------- + ----- ------------------- + | Nom_variable | La valeur | + ------------------------------------------- + ----- ------------------- + | 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 | tous | | 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 | affirmer | | 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_nevisa | 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 lignes dans le set (0.02 sec)
Le nombre de cœurs de la machine est de 8, c’est un
Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz
à partir de /proc/cpuinfo
Une dernière remarque: Exécuter les requêtes avec les index suggérés par RolandoMYSQLDBA. Les requêtes ont duré environ 11-20 secondes. Je tiens à souligner qu'il est crucial pour moi (ceci est la table principale d'un babillard) que la première requête sur un ID de fil retourne en moins d'une seconde, car il y a plus de 60 000 threads et google-bots explorent en permanence ces discussions.