Warum sind einfache SELECTs auf InnoDB 100x langsamer als auf MyISAM?


33

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_postTabelle in eine neue Tabelle kopiert (Beschreibung folgt) newbb_innopostund in InnoDB geändert. Die Tabellen enthalten derzeit jeweils 5,390,146Einträ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_poolGröß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.


Kommentare sind nicht für längere Diskussionen gedacht. Dieses Gespräch war in den Chat verschoben .
Paul White sagt GoFundMonica

Antworten:


24

IHRE ANFRAGE

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

Auf den ersten Blick sollte diese Abfrage nur 1,1597% (62510 von 5390146) der Tabelle berühren. Bei der Schlüsselverteilung von threadid 51506 sollte es schnell gehen.

REALITY-CHECK

Unabhängig davon, welche Version von MySQL (Oracle, Percona, MariaDB) Sie verwenden, kann keine von ihnen gegen einen gemeinsamen Gegner antreten: Die InnoDB-Architektur.

InnoDB-Architektur

CLUSTERED INDEX

Bitte beachten Sie, dass an jeden Thread-ID-Eintrag ein Primärschlüssel angehängt ist. Dies bedeutet, dass beim Lesen aus dem Index eine Primärschlüsselsuche im ClusteredIndex (intern gen_clust_index) durchgeführt werden muss . Im ClusteredIndex enthält jede InnoDB-Seite sowohl Daten- als auch PRIMARY KEY-Indexinformationen. Weitere Informationen finden Sie in meinem Beitrag Best of MyISAM und InnoDB .

REDUNDANTE INDEXE

Sie haben viel Durcheinander in der Tabelle, da einige Indizes die gleichen führenden Spalten haben. MySQL und InnoDB müssen durch das Index-Durcheinander navigieren, um zu den benötigten BTREE-Knoten zu gelangen. Sie sollten dieses Durcheinander reduzieren, indem Sie Folgendes ausführen:

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

Warum diese Indizes entfernen?

  • Die ersten drei Indizes beginnen mit threadid
  • threadid_2 und threadid_visible_dateline beginnen Sie mit den gleichen drei Spalten
  • threadid_visible_dateline postid wird nicht benötigt, da es sich um den PRIMARY KEY handelt und dieser eingebettet ist

PUFFER CACHING

Der InnoDB-Pufferpool speichert Daten und Indexseiten zwischen. MyISAM speichert nur Indexseiten.

Nur in diesem Bereich verschwendet MyISAM keine Zeit mit dem Zwischenspeichern von Daten. Das liegt daran, dass es nicht zum Zwischenspeichern von Daten entwickelt wurde. InnoDB speichert jede Daten- und Indexseite (und deren Großmutter) zwischen, die es berührt. Wenn Ihr InnoDB-Pufferpool zu klein ist, können Sie in einer Abfrage Seiten zwischenspeichern, Seiten ungültig machen und Seiten entfernen.

TISCHLAYOUT

Sie könnten etwas Platz aus der Reihe rasieren, indem Sie importthreadidund in Betracht ziehenimportpostid . Sie haben sie als BIGINTs. Sie belegen im ClusteredIndex 16 Bytes pro Zeile.

Sie sollten dies ausführen

SELECT importthreadid,importpostid FROM newbb_innopost PROCEDURE ANALYSE();

Hiermit wird empfohlen, welche Datentypen diese Spalten für das angegebene Dataset haben sollten.

FAZIT

MyISAM hat viel weniger zu kämpfen als InnoDB, insbesondere im Bereich Caching.

Während Sie die Größe von RAM ( 32GB) und die Version von MySQL ( Server version: 10.0.12-MariaDB-1~trusty-wsrep-log mariadb.org binary distribution, wsrep_25.10.r4002) enthüllt haben, gibt es noch andere Teile dieses Puzzles, die Sie nicht enthüllt haben

  • Die InnoDB-Einstellungen
  • Die Anzahl der Kerne
  • Andere Einstellungen von my.cnf

Wenn Sie diese Dinge zur Frage hinzufügen können, kann ich sie weiter ausführen.

UPDATE 28.08.2014 11:27 Uhr EDT

Sie sollten Threading erhöhen

innodb_read_io_threads = 64
innodb_write_io_threads = 16
innodb_log_buffer_size = 256M

Ich würde in Betracht ziehen, den Abfragecache zu deaktivieren. (Siehe meinen letzten Beitrag Warum ist query_cache_type standardmäßig deaktiviert? Starten Sie mit MySQL 5.6. )

query_cache_size = 0

Ich würde den Pufferpool erhalten

innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1

Bereinigungs-Threads erhöhen (wenn Sie DML für mehrere Tabellen ausführen)

innodb_purge_threads = 4

VERSUCHE ES !!!


Ich weiß, dass InnoDB in einem reinen Geschwindigkeitstest langsamer sein soll, aber in diesem Ausmaß? Ich habe gelesen, dass das MySQL-Team hart daran gearbeitet hat, diese Lücke zu schließen. Wir haben es immer noch mit einem 100-fachen Anstieg zu tun! Frage - sagen Sie, dass Abfragen dieser Art mit einem "direkten" nicht gruppierten B-Tree-Index (dh ohne die PK-Daten) besser bedient werden könnten? Wenn ja, warum wurde / wird dies nicht implementiert? Die Funktionalität, die das OP benötigt, ist definitiv kein marginaler Anwendungsfall.
Vérace

Können Sie einen Link zur Vollversion dieses Bildes hinzufügen? Einige Teile sind schwer zu lesen :-)
wässrig

@RolandMySQLDBA danke für die Information - Ich hoffe, Sie schlagen nicht vor, dass eine 100-fache Verlangsamung für InnoDB "normal" ist ... Ich könnte mit 2x oder 3x leben, aber 100x ist einfach zu viel. Wie gewünscht habe ich die fehlenden Informationen zu meiner Frage hinzugefügt :) Vielen Dank für die bisherigen Erklärungen! Anzahl der Kerne der Maschine ist 8.
Jollyroger

2
@watery Hier ist das Bild in voller Größe: scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing
RolandoMySQLDBA

1
Vielen Dank für Ihre Hilfe @RolandoMySQLDBA, leider haben auch diese letzten Optimierungen nicht geholfen, und die InnoDB benötigt ca. 11-20 Sekunden, um fertig zu sein. Ich habe basierend auf Ihrer Antwort versucht, alle Indizes zu löschen und einen Deckungsindex zu erstellen. Das hat sehr geholfen. Ohne Ihre Erklärung der Indizes hätte ich diese Lösung nicht gefunden. Überprüfe deine Antwort und schreibe mir selbst eine Antwort und erkläre, was ich getan habe :)
jollyroger

7

@RolandMySQLDBA hat den richtigen Hinweis zur Beantwortung der Frage gegeben. Das Problem scheint in der Abfrage zu liegen, und damit die Ergebnisse zurückgegeben werden können, muss jedes dieser Felder gelesen werden (irgendwie aus der Datenbank).

Ich habe alle Indizes außer dem gelöscht PRIMARY KEYund diesen neuen Index eingefügt:

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

Dieser Link erklärt, was hier passiert ( abdeckender Index ): Die abgefragten Felder der Abfrage postid,attachkönnen nun aus dem Schlüssel selbst extrahiert werden. Das erspart das Überprüfen der realen Daten und das Verwenden von E / A auf der Festplatte.

Alle Abfragen laufen jetzt mit 0,00 Sekunden .. :)

Vielen Dank für Ihre Hilfe.

Edit : Das eigentliche Grundproblem ist nicht gelöst, ich habe es nur mit dieser Technik umgangen. InnoDB muss in diesem Bereich dringend repariert werden.


Ich stehe vor dem gleichen Problem. Die Abfrage von myisma dauert 0,01 Sekunden, während innodb 60 Sekunden benötigt. Probieren Sie Ihre Vorschläge aus.
AMB,

@AMB - 0,01s riecht nach dem Abfrage-Cache. Mal wieder mit SQL_NO_CACHE.
Rick James

0

Basierend auf Ihrer Abfrage und Tabelle scheinen Sie Daten aus einer Zeitreihentabelle auszuwählen. Als solches kann es sein, dass die Abfragezeit langsam ist, weil Sie gleichzeitig einfügen?

Wenn diese beiden Dinge zutreffen, kann ich dann vorschlagen, sich alternativ mit ScaleDB zu befassen? Sie werden immer noch auf MariaDB sein, nur (vielleicht) eine passendere Engine.

http://www.scaledb.com - Homepage http://www.scaledb.com/download-form.php - unser Produkt


2
Sie sollten hinzufügen, dass die Hauptausgabe nicht kostenlos ist.
ypercubeᵀᴹ

0

Mit beiden Engines wird die Abfrage viel schneller ausgeführt

INDEX(threadid, attach, postid)

Dies liegt daran, dass es sich um einen "abdeckenden" Index handelt, der praktisch auf die gleiche Weise funktioniert (unter Verwendung des Index BTree).

Außerdem werde ich sagen, dass dies für beide Engines auf einem "kalten" Server nicht möglich ist :

62510 rows in set (0.13 sec)

Bitte verwenden Sie diese SQL_NO_CACHEOption, wenn Timings ausgeführt werden. Wir möchten nicht, dass der Abfrage-Cache die Schlussfolgerungen verfälscht.

Ein weiterer schneller Ansatz (unabhängig vom I / O-Caching):

Verwenden Sie InnoDB und wechseln Sie von PRIMARY KEY (postid)zu

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

Der Grund dafür ist , dass diese alle relevanten Reihen verursachen benachbart sein, um dadurch die weniger I / O, etc. Das INDEX(postid)ist zu halten AUTO_INCREMENTglücklich. Vorsichtsmaßnahme: Dies führt zu Problemen mit allen Sekundärschlüsseln - einige sind schneller, andere langsamer.


0

Obwohl dies nicht direkt auf @jollyroger zutrifft, da er bereits die richtige Einstellung hat, wurde die Änderung innodb_buffer_pool_sizedes RAM- Werts auf 70% erheblich verbessert, wie in Warum ist myisam langsamer als Innodb erläutert

Zunächst MyISAMwar langsam, aber oke. Dann InnoDBmachten die Dinge schlimm, ähnlich wie die 100x langsamer in dieser Frage und nach dem Ändern der Einstellung wurde InnoDBdann 10x schneller MyISAM.

Meine Standardeinstellung war 8 MB, was viel zu wenig ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.