Ich habe ein ziemlich nerviges Problem. Ich möchte INNODB als meine Hauptdatenbank-Engine verwenden und auf MyISAM verzichten, da ich das erstere für die Verwendung von Galera-Cluster zur Redundanz benötige.
Ich habe die newbb_post
Tabelle in eine neue Tabelle kopiert (Beschreibung folgt) newbb_innopost
und in InnoDB geändert. Die Tabellen enthalten derzeit jeweils 5,390,146
Einträge.
Wenn Sie diese Auswahlen in einer neu gestarteten Datenbank ausführen (an dieser Stelle ist also kein Caching erforderlich!), Liefert die Datenbank die folgenden Ergebnisse (ohne die vollständige Ausgabe, bitte beachten Sie, dass ich die Datenbank nicht einmal auffordere, die Ergebnisse zu sortieren):
SELECT post.postid, post.attach FROM newbb_post AS post WHERE post.threadid = 51506; . . | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 62510 Zeilen im Satz (0,13 Sek.)
SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; . . | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 62510 Zeilen im Satz (1 Min. 22,19 Sek.)
0,13 Sekunden bis 86,19 Sekunden (!)
Ich frage mich, warum das passiert. Ich habe hier einige Antworten zu Stackexchange gelesen, die InnoDB betreffen, und einige schlagen vor, die innodb_buffer_pool
Größe auf 80% des installierten Arbeitsspeichers zu erhöhen . Dies wird das Problem nicht lösen, dass die anfängliche Abfrage einer bestimmten ID mindestens 50-mal länger dauert und den gesamten Web-Server zum Stillstand bringt, wodurch Verbindungen und Abfragen für die Datenbank in die Warteschlange gestellt werden. Anschließend wird der Cache / Puffer möglicherweise aktiviert, die Datenbank enthält jedoch mehr als 100.000 Threads. Daher ist es sehr wahrscheinlich, dass der Cache nie alle relevanten Abfragen enthält, die verarbeitet werden sollen.
Die obigen Abfragen sind einfach (keine Verknüpfungen) und alle Schlüssel werden verwendet:
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | id | select_type | tisch | Typ | Mögliche_Tasten | Schlüssel | key_len | ref | Reihen | Extra | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | 1 | EINFACH | post | ref | threadid, threadid_2, threadid_visible_dateline | threadid | 4 | const | 120144 | | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
Dies ist die MyISAM-Tabelle:
CREATE TABLE `newbb_post` ( `postid` int (10) ohne Vorzeichen NOT NULL AUTO_INCREMENT, `threadid` int (10) ohne Vorzeichen NOT NULL DEFAULT '0', `parentid` int (10) ohne Vorzeichen 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) ohne Vorzeichen NOT NULL DEFAULT '0', `pagetext` mediumtext, `allowmilie` smallint (6) NOT NULL DEFAULT '0', `showsignature` smallint (6) NOT NULL DEFAULT '0', `ipaddress` varchar (15) NOT NULL DEFAULT '', `iconid` smallint (5) ohne Vorzeichen NOT NULL DEFAULT '0', `visible` smallint (6) NOT NULL DEFAULT '0', `attach` smallint (5) ohne Vorzeichen NOT NULL DEFAULT '0', `infraction` smallint (5) ohne Vorzeichen NOT NULL DEFAULT '0', `reportthreadid` int (10) ohne Vorzeichen NOT NULL DEFAULT '0', `importthreadid` bigint (20) NOT NULL DEFAULT '0', `importpostid` bigint (20) NOT NULL DEFAULT '0', `conversioned_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`), KEY `conversion_2_utf8` (` conversion_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 DEFAULT CHARSET = latin1
und das ist die InnoDB-Tabelle (es ist genau das gleiche):
CREATE TABLE `newbb_innopost` ( `postid` int (10) ohne Vorzeichen NOT NULL AUTO_INCREMENT, `threadid` int (10) ohne Vorzeichen NOT NULL DEFAULT '0', `parentid` int (10) ohne Vorzeichen 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) ohne Vorzeichen NOT NULL DEFAULT '0', `pagetext` mediumtext, `allowmilie` smallint (6) NOT NULL DEFAULT '0', `showsignature` smallint (6) NOT NULL DEFAULT '0', `ipaddress` varchar (15) NOT NULL DEFAULT '', `iconid` smallint (5) ohne Vorzeichen NOT NULL DEFAULT '0', `visible` smallint (6) NOT NULL DEFAULT '0', `attach` smallint (5) ohne Vorzeichen NOT NULL DEFAULT '0', `infraction` smallint (5) ohne Vorzeichen NOT NULL DEFAULT '0', `reportthreadid` int (10) ohne Vorzeichen NOT NULL DEFAULT '0', `importthreadid` bigint (20) NOT NULL DEFAULT '0', `importpostid` bigint (20) NOT NULL DEFAULT '0', `conversioned_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`), KEY `conversion_2_utf8` (` conversion_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
Server mit 32 GB RAM:
Serverversion: 10.0.12-MariaDB-1 ~ trusty-wsrep-log mariadb.org-Binärdistribution, wsrep_25.10.r4002
Wenn Sie alle Einstellungen für innodb_-Variablen benötigen, kann ich diese an diesen Beitrag anhängen.
Aktualisieren:
Ich habe ALLE Indizes außer dem Primärindex gelöscht, danach sah das Ergebnis so aus:
. . | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 62510 Zeilen im Satz (29,74 Sek.)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | id | select_type | tisch | Typ | Mögliche_Tasten | Schlüssel | key_len | ref | Reihen | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | 1 | EINFACH | post | ALL | NULL | NULL | NULL | NULL | 5909836 | Verwenden von where | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + 1 Reihe im Satz (0,00 Sek.)
Danach habe ich nur einen Index zurück zum Mix hinzugefügt, threadid, die Ergebnisse waren die folgenden:
. . | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 62510 Zeilen im Satz (11,58 Sek.)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | id | select_type | tisch | Typ | Mögliche_Tasten | Schlüssel | key_len | ref | Reihen | Extra | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | 1 | EINFACH | post | ref | threadid | threadid | 4 | const | 124622 | | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + 1 Reihe im Satz (0,00 Sek.)
Seltsamerweise dauerte der vollständige Scan ohne relevante Indizes nur 29 Sekunden, verglichen mit 88 Sekunden bei Verwendung von Indizes (!).
Mit nur einem perfekt zugeschnittenen Index dauert es immer noch 11 Sekunden, bis der Vorgang abgeschlossen ist - immer noch viel zu langsam für den tatsächlichen Gebrauch.
Update 2:
Ich habe MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) auf einem anderen Server mit genau derselben Hardwarekonfiguration und genau derselben Datenbank / denselben Tabellen eingerichtet.
Die Ergebnisse sind nahezu identisch, zunächst die MyISAM-Tabelle:
. . | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 62510 Zeilen im Satz (0,14 Sek.)
Und das ist das Ergebnis der InnoDB-Tabelle
. . | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 62510 Zeilen im Satz (1 Min. 17,63 Sek.)
UPDATE 3: der Inhalt von my.cnf
# MariaDB-Datenbankserver-Konfigurationsdatei. # # Sie können diese Datei in eines der folgenden Verzeichnisse kopieren: # - "/etc/mysql/my.cnf", um globale Optionen festzulegen, # - "~ / .my.cnf", um benutzerspezifische Optionen festzulegen. # # Man kann alle langen Optionen verwenden, die das Programm unterstützt. # Führen Sie das Programm mit --help aus, um eine Liste der verfügbaren Optionen zu erhalten # --print-Defaults, um zu sehen, was es tatsächlich verstehen und verwenden würde. # # Erläuterungen siehe # http://dev.mysql.com/doc/mysql/de/server-system-variables.html # Dies wird an alle MySQL-Clients weitergegeben # Es wurde berichtet, dass Passwörter mit Häkchen / Anführungszeichen versehen werden sollten # besonders wenn sie "#" Zeichen enthalten ... # Denken Sie daran, /etc/mysql/debian.cnf zu bearbeiten, wenn Sie die Position des Sockets ändern. [Klient] port = 3306 socket = /var/run/mysqld/mysqld.sock # Hier finden Sie Einträge für bestimmte Programme # Die folgenden Werte setzen voraus, dass Sie mindestens 32M RAM haben # Dies war formal als [safe_mysqld] bekannt. Beide Versionen werden derzeit analysiert. [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nett = 0 [mysqld] # # * Grundeinstellungen # user = 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 = de_DE überspringen-extern-verriegeln # # Anstatt zu überspringen, wird standardmäßig nur noch zugehört # localhost ist kompatibler und nicht weniger sicher. Bindeadresse = 127.0.0.1 # # * Feintuning # 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 # # Dies ersetzt das Startskript und überprüft bei Bedarf MyISAM-Tabellen # das erste Mal, wenn sie berührt werden. Im Fehlerfall eine Kopie anfertigen und eine Reparatur versuchen. myisam_recover = BACKUP key_buffer_size = 128 MB # 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 # # * Abfrage-Cache-Konfiguration # # Nur winzige Ergebnismengen zwischenspeichern, damit wir mehr in den Abfragecache passen. query_cache_limit = 128 KB query_cache_size = 64M # für schreibintensivere Setups auf DEMAND oder OFF setzen #query_cache_type = DEMAND # # * Protokollierung und Replikation # # Beide Standorte werden durch den Cronjob gedreht. # Beachten Sie, dass dieser Protokolltyp ein Leistungskiller ist. # Ab 5.1 können Sie das Log zur Laufzeit aktivieren! #general_log_file = /var/log/mysql/mysql.log #general_log = 1 # # Die Fehlerprotokollierung wird aufgrund von /etc/mysql/conf.d/mysqld_safe_syslog.cnf an syslog gesendet. # # Wir möchten Informationen zu Netzwerkfehlern und dergleichen erhalten log_warnings = 2 # # Aktivieren Sie das Protokoll für langsame Abfragen, um Abfragen mit besonders langer Dauer anzuzeigen #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 # Protokollabfragen, die keine Indizes verwenden #log_slow_admin_statements # # Folgendes kann zur einfachen Wiedergabe von Sicherungsprotokollen oder zur Replikation verwendet werden. # Hinweis: Wenn Sie einen Replikations-Slave einrichten, lesen Sie README.Debian # andere Einstellungen, die Sie möglicherweise ändern müssen. # 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 # nicht fabelhaft für die Leistung, aber sicherer #sync_binlog = 1 expire_logs_days = 10 max_binlog_size = 100M # Sklaven #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 #schreibgeschützt # # Wenn Anwendungen dies unterstützen, verhindert dieser strengere sql_mode einige # Fehler wie das Einfügen ungültiger Daten usw. #sql_mode = NO_ENGINE_SUBSTITUTION, TRADITIONAL # # * InnoDB # # InnoDB ist standardmäßig mit einer 10-MB-Datendatei in / var / lib / mysql / aktiviert. # Lesen Sie das Handbuch für weitere InnoDB-bezogene Optionen. Da sind viele! default_storage_engine = InnoDB # Sie können die Größe der Protokolldatei nicht einfach ändern, da hierfür spezielle Verfahren erforderlich sind #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 # # * Sicherheitsfunktionen # # Lesen Sie auch das Handbuch, wenn Sie Chroot wollen! # chroot = / var / lib / mysql / # # Für die Erzeugung von SSL-Zertifikaten empfehle ich die OpenSSL-GUI "tinyca". # # ssl-ca = /etc/mysql/cacert.pem # ssl-cert = /etc/mysql/server-cert.pem # ssl-key = / etc / mysql / server-key.pem [mysqldump] schnell Anführungszeichen max_allowed_packet = 16M [MySQL] # no-auto-rehash # schnellerer Start von MySQL, aber keine Tab-Vervollständigung [isamchk] key_buffer = 16M # # * WICHTIG: Zusätzliche Einstellungen, die die Einstellungen aus dieser Datei überschreiben können! # Die Dateien müssen mit '.cnf' enden, sonst werden sie ignoriert. # ! includedir /etc/mysql/conf.d/
Und der Inhalt der inno-Variablen:
MariaDB [(none)]> SHOW VARIABLES LIKE 'inno%'; + ------------------------------------------- + ----- ------------------- + | Variablenname | Wert | + ------------------------------------------- + ----- ------------------- + | 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 | AUS | | innodb_api_enable_binlog | AUS | | innodb_api_enable_mdl | AUS | | innodb_api_trx_level | 0 | | innodb_autoextend_increment | 64 | | innodb_autoinc_lock_mode | 1 | | innodb_buffer_pool_dump_at_shutdown | AUS | | innodb_buffer_pool_dump_now | AUS | | innodb_buffer_pool_filename | ib_buffer_pool | | innodb_buffer_pool_instances | 8 | | innodb_buffer_pool_load_abort | AUS | | innodb_buffer_pool_load_at_startup | AUS | | innodb_buffer_pool_load_now | AUS | | innodb_buffer_pool_populate | AUS | | innodb_buffer_pool_size | 21474836480 | | innodb_change_buffer_max_size | 25 | | innodb_change_buffering | alle | | innodb_checksum_algorithm | innodb | | innodb_checksums | ON | | innodb_cleaner_lsn_age_factor | high_checkpoint | | innodb_cmp_per_index_enabled | AUS | | 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 | behaupten | | innodb_data_file_path | ibdata1: 12M: autoextend | | innodb_data_home_dir | | | innodb_disable_sort_file_cache | AUS | | innodb_doublewrite | ON | | innodb_empty_free_list_algorithm | backoff | | innodb_fake_changes | AUS | | 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 | AUS | | innodb_force_recovery | 0 | | innodb_foreground_preflush | exponential_backoff | | innodb_ft_aux_table | | | innodb_ft_cache_size | 8000000 | | innodb_ft_enable_diag_print | AUS | | 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 | AUS | | innodb_lock_wait_timeout | 50 | | innodb_locking_fake_changes | ON | | innodb_locks_unsafe_for_binlog | AUS | | innodb_log_arch_dir | ./ | | innodb_log_arch_expire_sec | 0 | | innodb_log_archive | AUS | | 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 | AUS | | innodb_page_size | 16384 | | innodb_print_all_deadlocks | AUS | | innodb_purge_batch_size | 300 | | innodb_purge_threads | 1 | | innodb_random_read_ahead | AUS | | innodb_read_ahead_threshold | 56 | | innodb_read_io_threads | 4 | | innodb_read_only | AUS | | innodb_replication_delay | 0 | | innodb_rollback_on_timeout | AUS | | 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 | AUS | | innodb_stats_persistent | ON | | innodb_stats_persistent_sample_pages | 20 | | innodb_stats_sample_pages | 8 | | innodb_stats_transient_sample_pages | 8 | | innodb_status_output | AUS | | innodb_status_output_locks | AUS | | innodb_strict_mode | AUS | | 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 | AUS | | innodb_undo_directory | . | | innodb_undo_logs | 128 | | innodb_undo_tablespaces | 0 | | innodb_use_atomic_writes | AUS | | innodb_use_fallocate | AUS | | innodb_use_global_flush_log_at_trx_commit | ON | | innodb_use_native_aio | ON | | innodb_use_stacktrace | AUS | | innodb_use_sys_malloc | ON | | innodb_version | 5.6.17-65.0 | | innodb_write_io_threads | 4 | + ------------------------------------------- + ----- ------------------- + 143 Zeilen im Satz (0,02 Sek.)
Die Anzahl der Kerne der Maschine ist 8, es ist ein
Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz
ab /proc/cpuinfo
Eine letzte Anmerkung: Die Abfragen wurden mit den von RolandoMYSQLDBA vorgeschlagenen Indizes ausgeführt, und die Abfragen dauerten jeweils ca. 11-20 Sekunden. Ich möchte darauf hinweisen, dass es für mich von entscheidender Bedeutung ist (dies ist die Haupttabelle eines Bulletin Boards), dass die erste Abfrage nach einer Thread-ID in weniger als einer Sekunde erfolgt, da ständig mehr als 60.000 Threads und Google-Bots gecrawlt werden diese Fäden.