Чому прості SELECT на InnoDB 100x повільніше, ніж на MyISAM?


33

У мене досить дратівлива проблема. Я хочу використовувати INNODB в якості свого основного двигуна бази даних і відмовитися від MyISAM, оскільки мені потрібен перший для використання галера-кластера для надмірності.

Я скопіював (опис випливає) newbb_postтаблицю в нову таблицю під назвою newbb_innopostта змінив її на InnoDB. Наразі таблиці містять 5,390,146записи кожної.

Виконуючи ці виділення на щойно запущеній базі даних (тому в даний момент ніякого кешування не задіяно!) База даних дає такі результати (опускаючи повний вихід, будь ласка, зверніть увагу, що я навіть не прошу базу даних сортувати результати):

ВИБІРТЕ post.postid, post.attach ВІД newbb_post AS post WHERE post.threadid = 51506;

.
.
| 5401593 | 0 |
| 5401634 | 0 |
+ --------- + -------- +
62510 рядків у наборі (0,13 сек)
ВИБІРТЕ post.postid, post.attach ВІД newbb_innopost ЯК пост, ЩО post.threadid = 51506;
.
.
| 5397410 | 0 |
| 5397883 | 0 |
+ --------- + -------- +
62510 рядків у наборі (1 хв 22,19 сек)

0,13 секунди до 86,19 секунди (!)

Мені цікаво, чому це відбувається. Я прочитав тут деякі відповіді на Stackexchange, що стосуються InnoDB, а деякі пропонують збільшити innodb_buffer_poolрозмір до 80% встановленої оперативної пам’яті. Це не вирішить проблему, що початковий запит до певного ідентифікатора займе щонайменше на 50 разів довше і затримає весь веб-сервер, виклавши в чергу з'єднання та запити до бази даних. Згодом кеш / буфер може запуститися, але в цій базі даних є понад 100 000 потоків, тому велика ймовірність, що кеш ніколи не буде містити всі відповідні запити, які будуть обслуговуватися.

Наведені вище запити прості (без приєднання), і використовуються всі клавіші:

ПОЯСНІТЬ ВИБІР post.postid, post.attach ВІД newbb_innopost AS post ДЕ post.threadid = 51506;
+ ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
| id | select_type | стіл | тип | можливі_ключі | ключ | key_len | посилання | ряди | Додатковий |
+ ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
| 1 | ПРОСТО | посада | посилання | nitid, threadid_2, threadid_visible_dateline | різьбові | 4 | const | 120144 | |
+ ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +

Це таблиця MyISAM:

СТВОРИТИ ТАБЛИЦЮ `newbb_post` (
  `postid` int (10) без підпису NOT NULL AUTO_INCREMENT,
  `threadid` int (10) без підпису НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `parentid` int (10) без підпису NOT NULL DEFAULT '0',
  `ім'я користувача` varchar (100) НЕ НЕЗАЄМНЕ ЗАВДАННЯ",
  `userid` int (10) без підпису NOT NULL DEFAULT '0',
  `title` varchar (250) NOT NULL DEFAULT '',
  `dateline` int (10) без підпису НЕ НУЛЬКИЙ ЗАВДАННЯ" 0 ",
  `pagetext` середній текст,
  `enablemilie` smallint (6) NOT NULL DEFAULT '0',
  `showignature` smallint (6) NOT NULL DEFAULT '0',
  `ipaddress` varchar (15) НІЛЬКИЙ ЗАБЕЗПЕЧЕНЬ",
  `iconid` smallint (5) не підписаний НЕ НЕЗАЄМНОГО ЗАВДАННЯ '0',
  `видимий` smallint (6) NOT NULL DEFAULT '0',
  `attach` smallint (5) без підпису NOT NULL DEFAULT '0',
  `infraction` smallint (5) без підпису НЕ НЕЗАЄМНЕ ЗАВДАННЯ '0',
  `reportthreadid` int (10) без підпису НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `importthreadid` bigint (20) НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `importpostid` bigint (20) НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `convert_2_utf8` int (11) НЕ NULL,
  `htmlstate` enum ('вимкнено', 'увімкнено', 'on_nl2br') НЕ NULL DEFAULT 'on_nl2br',
  ПЕРШИЙ КЛЮЧ (`postid`),
  КЛЮЧОВИЙ `threadid` (` threadid`, `userid`),
  КЛЮЧОВИЙ `importpost_index` (` importpostid`),
  КЛЮЧОВИЙ `dateline` (` дательін`),
  КЛЮЧОВИЙ `threadid_2` (` threadid`, `видимий`,` dateline`),
  КЛЮЧ "перетворений_2_utf8` (` перетворений_2_utf8`),
  KEY `threadid_visible_dateline` (` threadid`, `видима`,` dateline`, `userid`,` postid`),
  KEY `ipaddress` (` ipaddress`),
  KEY `userid` (` userid`, `parentid`),
  KEY `user_date` (` userid`, `dateline`)
) ДВИГАТЕЛ = MyISAM AUTO_INCREMENT = 5402802 ЗАМОВЛЕННЯ ХАРАКТЕР = latin1

і це таблиця InnoDB (вона точно така ж):

СТВОРИТИ ТАБЛИЦЮ `newbb_innopost` (
  `postid` int (10) без підпису NOT NULL AUTO_INCREMENT,
  `threadid` int (10) без підпису НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `parentid` int (10) без підпису NOT NULL DEFAULT '0',
  `ім'я користувача` varchar (100) НЕ НЕЗАЄМНЕ ЗАВДАННЯ",
  `userid` int (10) без підпису NOT NULL DEFAULT '0',
  `title` varchar (250) NOT NULL DEFAULT '',
  `dateline` int (10) без підпису НЕ НУЛЬКИЙ ЗАВДАННЯ" 0 ",
  `pagetext` середній текст,
  `enablemilie` smallint (6) NOT NULL DEFAULT '0',
  `showignature` smallint (6) NOT NULL DEFAULT '0',
  `ipaddress` varchar (15) НІЛЬКИЙ ЗАБЕЗПЕЧЕНЬ",
  `iconid` smallint (5) не підписаний НЕ НЕЗАЄМНОГО ЗАВДАННЯ '0',
  `видимий` smallint (6) NOT NULL DEFAULT '0',
  `attach` smallint (5) без підпису NOT NULL DEFAULT '0',
  `infraction` smallint (5) без підпису НЕ НЕЗАЄМНЕ ЗАВДАННЯ '0',
  `reportthreadid` int (10) без підпису НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `importthreadid` bigint (20) НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `importpostid` bigint (20) НЕ НУЛЬКИЙ ЗАВДАННЯ '0',
  `convert_2_utf8` int (11) НЕ NULL,
  `htmlstate` enum ('вимкнено', 'увімкнено', 'on_nl2br') НЕ NULL DEFAULT 'on_nl2br',
  ПЕРШИЙ КЛЮЧ (`postid`),
  КЛЮЧОВИЙ `threadid` (` threadid`, `userid`),
  КЛЮЧОВИЙ `importpost_index` (` importpostid`),
  КЛЮЧОВИЙ `dateline` (` дательін`),
  КЛЮЧОВИЙ `threadid_2` (` threadid`, `видимий`,` dateline`),
  КЛЮЧ "перетворений_2_utf8` (` перетворений_2_utf8`),
  KEY `threadid_visible_dateline` (` threadid`, `видима`,` dateline`, `userid`,` postid`),
  KEY `ipaddress` (` ipaddress`),
  KEY `userid` (` userid`, `parentid`),
  KEY `user_date` (` userid`, `dateline`)
) ДВИГАТЕЛ = InnoDB AUTO_INCREMENT = 5402802 ЗАМОВЛЕННЯ ХАРАКТЕР = latin1

Сервер з 32 ГБ оперативної пам’яті:

Версія сервера: 10.0.12-MariaDB-1 ~ trusty-wsrep-log mariadb.org бінарний дистрибутив, wsrep_25.10.r4002

Якщо вам потрібні всі параметри змінних innodb_, я можу приєднати це до цієї публікації.

Оновлення:

Я скинув ВСІ індекси крім основного індексу, після чого результат виглядав так:

.
.
| 5402697 | 0 |
| 5402759 | 0 |
+ --------- + -------- +
62510 рядків у наборі (29,74 сек)
ПОЯСНІТЬ ВИБІР post.postid, post.attach ВІД newbb_innopost AS post ДЕ post.threadid = 51506;
+ ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- +
| id | select_type | стіл | тип | можливі_ключі | ключ | key_len | посилання | ряди | Додатковий |
+ ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- +
| 1 | ПРОСТО | посада | ВСІ | NULL | NULL | NULL | NULL | 5909836 | Використання де |
+ ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- +
1 ряд у наборі (0,00 сек)

Після цього я щойно додав один індекс до суміші, ниткові, результати були такі:

.
.
| 5402697 | 0 |
| 5402759 | 0 |
+ --------- + -------- +
62510 рядків у наборі (11,58 сек)
ПОЯСНІТЬ ВИБІР post.postid, post.attach ВІД newbb_innopost AS post ДЕ post.threadid = 51506;
+ ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- +
| id | select_type | стіл | тип | можливі_ключі | ключ | key_len | посилання | ряди | Додатковий |
+ ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- +
| 1 | ПРОСТО | посада | посилання | різьбові | різьбові | 4 | const | 124622 | |
+ ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- +
1 ряд у наборі (0,00 сек)

Дивно, що без відповідних індексів повне сканування зайняло лише 29 секунд порівняно з 88 секундами за допомогою індексів (!).

За допомогою лише одного ідеально підібраного індексу для завершення потрібно ще 11 секунд - все ще занадто повільно для використання в реальному світі.

Оновлення 2:

Я встановлюю MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) на іншому сервері з точно такою ж конфігурацією обладнання та точно такою ж базою даних / таблицями.

Результати майже однакові, спочатку таблиця MyISAM:

.
.
| 5401593 | 0 |
| 5401634 | 0 |
+ --------- + -------- +
62510 рядків у наборі (0,14 сек)

І це результат таблиці InnoDB

.
.
| 5397410 | 0 |
| 5397883 | 0 |
+ --------- + -------- +
62510 рядків у наборі (1 хв 17,63 сек)

ОНОВЛЕННЯ 3: вміст my.cnf

# Конфігураційний файл сервера баз даних MariaDB.
#
# Ви можете скопіювати цей файл в один із:
# - "/etc/mysql/my.cnf" для встановлення глобальних параметрів,
# - "~ / .my.cnf", щоб встановити конкретні параметри.
# 
# Можна використовувати всі довгі параметри, які підтримує програма.
# Запустіть програму за допомогою --help, щоб отримати список доступних варіантів та
# --print-за замовчуванням, щоб побачити, що воно насправді зрозуміло б і використовувати.
#
# Пояснення див
# http://dev.mysql.com/doc/mysql/uk/server-system-variables.html

# Це буде передано всім клієнтам mysql
# Повідомлялося, що паролі повинні бути додані тиками / лапками
# особливо, якщо вони містять символи "#" ...
# Не забудьте відредагувати /etc/mysql/debian.cnf під час зміни місця розташування сокета.
[клієнт]
порт = 3306
socket = /var/run/mysqld/mysqld.sock

# Ось записи для деяких конкретних програм
# Наступні значення припускають, що у вас є щонайменше 32 млн баран

# Це офіційно було відомо як [safe_mysqld]. Наразі обидві версії розібрані.
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
приємно = 0

[mysqld]
#
# * Основні налаштування
#
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
порт = 3306
basedir = / usr
datadir = / var / lib / mysql
tmpdir = / tmp
lc_messages_dir = / usr / share / mysql
lc_messages = en_US
пропускний-зовнішній-замикаючий
#
# Замість пропускної мережі зараз за промовчанням слухати потрібно лише
# localhost, який більш сумісний і не менш безпечний.
bind-address = 127.0.0.1
#
# * Тонка настройка
#
max_connections = 100
connect_timeout = 5
wait_timeout = 600
max_allowed_packet = 16М
thread_cache_size = 128
sort_buffer_size = 4М
bulk_insert_buffer_size = 16М
tmp_table_size = 32М
max_heap_table_size = 32М
#
# * MyISAM
#
# Це замінює сценарій запуску і при необхідності перевіряє таблиці MyISAM
# перший час їх торкаються. Після помилки зробіть копію та спробуйте відновити.
myisam_recover = НАЗАД
key_buffer_size = 128М
# open-files-limit = 2000
table_open_cache = 400
myisam_sort_buffer_size = 512М
concurrent_insert = 2
read_buffer_size = 2М
read_rnd_buffer_size = 1М
#
# * Конфігурація кешу запитів
#
# Кеш лише невеликих наборів результатів, тому ми можемо більше вміщуватись у кеші запитів.
query_cache_limit = 128 К
query_cache_size = 64М
# для більш інтенсивних налаштувань запису, встановлених на DEMAND або OFF
#query_cache_type = ДЕМАНТА
#
# * Реєстрація та реплікація
#
# Обидва місця обертаються за допомогою кронштейну.
# Будьте в курсі, що цей тип журналу є вбивцею продуктивності.
# З 5.1 ви можете включити журнал під час виконання!
#general_log_file = /var/log/mysql/mysql.log
#general_log = 1
#
# Журнал помилок переходить у syslog через /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
#
# ми хочемо знати про мережеві помилки та подібне
log_warnings = 2
#
# Увімкніть повільний журнал запитів, щоб переглядати запити з особливо великою тривалістю
#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-use-indexes
#log_slow_admin_statements
#
# Наступне може бути використане як просте відтворення журналів резервного копіювання або для реплікації.
# Примітка: якщо ви налаштовуєте підлеглий реплікацію, див. README.Debian про
# інші налаштування, які можуть знадобитися змінити
# сервер-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
# не феєричність виконання, але безпечніша
#sync_binlog = 1
expire_logs_days = 10
max_binlog_size = 100М
# раби
#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
#лише для читання
#
# Якщо програми підтримують це, цей суворіший sql_mode перешкоджає деяким
# помилки, такі як вставлення недійсних дат тощо
#sql_mode = NO_ENGINE_SUBSTITUTION, ТРАДИЦІОНАЛЬНА
#
# * InnoDB
#
# InnoDB увімкнено за допомогою типового файлу даних 10 МБ в / var / lib / mysql /.
# Прочитайте посібник для отримання додаткових параметрів, пов'язаних з InnoDB. Тут багато!
default_storage_engine = InnoDB
# ви не можете просто змінити розмір файлу журналу, потрібна спеціальна процедура
#innodb_log_file_size = 50М
innodb_buffer_pool_size = 20G
innodb_log_buffer_size = 8М
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 400
innodb_flush_method = O_DIRECT
#
# * Особливості безпеки
#
# Читайте також посібник, якщо хочете chroot!
# chroot = / var / lib / mysql /
#
# Для генерації сертифікатів SSL я рекомендую графічний інтерфейс OpenSSL "tinyca".
#
# ssl-ca = / etc / mysql / cacert.pem
# ssl-cert = / etc / mysql / server-cert.pem
# ssl-key = / etc / mysql / server-key.pem



[mysqldump]
швидкий
цитати-імена
max_allowed_packet = 16М

[mysql]
# no-auto-rehash # швидший запуск mysql, але відсутність вкладки

[isamchk]
key_buffer = 16М

#
# * ВАЖЛИВО: Додаткові параметри, які можуть змінювати параметри цього файлу!
# Файли повинні закінчуватися символом ".cnf", інакше вони будуть ігноровані.
#
! Includir /etc/mysql/conf.d/

І вміст змінних ina:

MariaDB [(none)]> ПОКАЗУЙТЕ ВАРІАБЛІСЬКІ ПОДИХНІТЬ 'невинні%';
+ ------------------------------------------- + ----- ------------------- +
| Ім'я змінної | Значення |
+ ------------------------------------------- + ----- ------------------- +
| 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 | ВИКЛ. |
| innodb_api_enable_binlog | ВИКЛ. |
| innodb_api_enable_mdl | ВИКЛ. |
| innodb_api_trx_level | 0 |
| innodb_autoextend_increment | 64 |
| innodb_autoinc_lock_mode | 1 |
| innodb_buffer_pool_dump_at_shutdown | ВИКЛ. |
| innodb_buffer_pool_dump_now | ВИКЛ. |
| innodb_buffer_pool_filename | ib_buffer_pool |
| innodb_buffer_pool_in вещества | 8 |
| innodb_buffer_pool_load_abort | OFF |
| innodb_buffer_pool_load_at_startup | ВИКЛ. |
| 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 | всі |
| 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 washing | стверджувати |
| 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 | Антилопа |
| innodb_file_format_check | ON |
| innodb_file_format_max | Антилопа |
| 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_compression_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 | ВИКЛ. |
| 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 | ВИКЛ. |
| 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 рядки в наборі (0,02 сек)

Кількість ядер машини 8, це а

Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz як на /proc/cpuinfo

Останнє зауваження: розміщуйте запити за допомогою індексів, запропонованих RolandoMYSQLDBA, і запити займали приблизно 11-20s кожен. Я хочу зазначити, що для мене вирішальне значення (це головна таблиця дошки оголошень), що перший запит про нитковій частині повертається менше ніж за секунду, оскільки існує понад 60 000 ниток, і Google-боти постійно повзають ці нитки.


Коментарі не для розширеного обговорення; ця розмова перенесена в чат .
Пол Білий каже, що GoFundMonica

Відповіді:


24

ВАШ ЗАПИТ

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

На перший погляд, цей запит повинен торкатися лише 1,1597% (62510 з 5390146) таблиці. Слід швидко отримати ключовий розподіл різьбового 51506.

ПЕРЕВІРИ РЕАЛЬНОСТІ

Незалежно від того, якою версією MySQL (Oracle, Percona, MariaDB) ви користуєтесь, жоден з них не може боротися з одним ворогом, якого мають усі спільні: Архітектура InnoDB.

Архітектура InnoDB

КЛАСТИРОВАНИЙ ІНДЕКС

Будь ласка, майте на увазі, що до кожного потокового запису доданий основний ключ Це означає, що коли ви читаєте з індексу, він повинен здійснювати пошук первинного ключа в ClusteredIndex (внутрішньо названий gen_clust_index) . У ClusteredIndex кожна сторінка InnoDB містить як дані, так і інформацію про індекс PRIMARY KEY. Дивіться мій пост Best of MyISAM та InnoDB для отримання додаткової інформації.

ПОНИЖЕННІ ІНДЕКСИ

У вас багато безладу в таблиці, оскільки деякі індекси мають однакові провідні стовпці. MySQL та InnoDB повинні орієнтуватися через індексне захаращення, щоб дістатися до потрібних BTREE-вузлів. Ви повинні зменшити цю безладу, виконавши наступне:

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

Навіщо знімати ці індекси?

  • Перші три індекси починаються з ниткових
  • threadid_2і threadid_visible_datelineпочніть з цих же трьох стовпців
  • threadid_visible_dateline не потрібен постид, оскільки це ПЕРШИЙ КЛЮЧ і він вбудований

КАФІНГ БУФЕРА

Пул буфера InnoDB кешує дані та індексні сторінки. MyISAM кешує лише індексні сторінки.

Тільки в цій області MyISAM не витрачає час на кешування даних. Це тому, що він не призначений для кешування даних. InnoDB кешує кожну сторінку даних та сторінку покажчиків (та її бабусю), на які вона торкається. Якщо ваш буфер InnoDB є занадто малим, ви можете кешувати сторінки, недійсні сторінки та видаляти всі сторінки за один запит.

ТАБЛИЧНА РОЗВИТКУ

Ви можете поголити трохи місця з ряду, розглянувши importthreadidі importpostid. Ви маєте їх як BIGINT. Вони займають 16 байт у ClusteredIndex за рядок.

Ви повинні запустити це

SELECT importthreadid,importpostid FROM newbb_innopost PROCEDURE ANALYSE();

Це дозволить рекомендувати, які типи даних мають бути у цих стовпцях для даного набору даних.

ВИСНОВОК

MyISAM має набагато менше проблем, ніж InnoDB, особливо в області кешування.

Поки ви виявили кількість оперативної пам’яті ( 32GB) та версії MySQL ( Server version: 10.0.12-MariaDB-1~trusty-wsrep-log mariadb.org binary distribution, wsrep_25.10.r4002), до цієї головоломки є ще інші фрагменти, які ви не розкрили

  • Налаштування InnoDB
  • Кількість ядер
  • Інші налаштування від my.cnf

Якщо ви можете додати ці питання до питання, я можу детальніше розібратися.

ОНОВЛЕННЯ 2014-08-28 11:27 EDT

Ви повинні збільшити різьблення

innodb_read_io_threads = 64
innodb_write_io_threads = 16
innodb_log_buffer_size = 256M

Я б подумав вимкнути кеш запитів (Дивіться мою останню публікацію. Чому запит query_cache_type відключений за замовчуванням, починаючи з MySQL 5.6? )

query_cache_size = 0

Я б зберегла буферний басейн

innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1

Збільште кількість потоків очищення (якщо ви використовуєте DML у кількох таблицях)

innodb_purge_threads = 4

СПРОБУВАТИ !!!


Я знаю, що InnoDB призначений бути повільнішим в чистому тесті на швидкість, але в цій мірі? Я читав, що команда MySQL наполегливо працює над тим, щоб закрити цю прогалину. Ми все ще маємо справу зі збільшенням в 100 разів! Питання - Ви хочете сказати, що запити такого характеру краще обслуговуватимуть "прямим" некластеризованим індексом B-дерева (тобто не включаючи дані ПК)? Якщо так, то чому це не було / не було реалізовано? Функціонал, необхідний ОП, безумовно, не є граничним випадком використання.
Vérace

Чи можете ви додати посилання на повнорозмірну версію цієї картинки? Деякі частини важко читати :-)
водяний

@RolandMySQLDBA дякую за інформацію - сподіваюся, ви не припускаєте, що 100-кратне уповільнення є "нормальним" для InnoDB ... Я міг би жити з 2x або 3x, але 100x просто занадто багато. За запитом я додав інформацію, яка відсутня, до мого запитання :) Дякую за пояснення поки! Кількість ядер машини - 8.
jollyroger

2
@watery Ось зображення в повному розмірі: scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing
RolandoMySQLDBA

1
Дякую за вашу допомогу @RolandoMySQLDBA, на жаль, навіть останні останні виправлення не допомогли, і InnoDB займає близько 11-20секунд. Я спробував щось на основі вашої відповіді - скидання всіх індексів та створення індексу покриття. Це дуже допомогло. Без вашого пояснення індексів я б не знайшов цього рішення. Збираюся перевірити свою відповідь і написати собі відповідь, пояснюючи, що я зробив :)
jollyroger

7

@RolandMySQLDBA дав правильну підказку для відповіді на питання. Здається, проблема полягає в запиті і в тому, що для повернення результатів кожне з цих полів має бути прочитане (якось із бази даних).

Я скинув усі індекси, окрім PRIMARY KEY, і вставив цей новий індекс:

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

Це посилання пояснює, що тут відбувається ( охоплює індекс ): Запитані поля запиту, які є, postid,attachтепер можуть бути вилучені з самого ключа. Це дозволяє економити перевірку реальних даних та використання вводу-виводу на жорсткому диску.

Усі запити зараз працюють за 0,00 секунд .. :)

Дякую всім за вашу допомогу.

Редагувати : фактична основна проблема не вирішена, я просто обійшов її цією технікою. InnoDB потребує серйозних виправлень у цій галузі.


я стикаюся з тим же питанням. запит myisma займає 0,01 секунди, а innodb - 60 секунд, я спробую ваші пропозиції.
AMB

@AMB - 0,01s пахне кешем запитів; час знову з SQL_NO_CACHE.
Рік Джеймс

0

Виходячи з вашого запиту та таблиці, схоже, що ви вибираєте дані selectikg з таблиці часових рядів. Таким чином, можливо, час запитів повільний, оскільки ви одночасно вставляєте?

Якщо ці дві речі істинні, то чи можу я запропонувати розглянути ScaleDB як альтернативу? Ви все одно будете на MariaDB, просто (можливо) більш відповідний двигун.

http://www.scaledb.com - домашня сторінка http://www.scaledb.com/download-form.php - наш продукт


2
Слід додати, що основне видання не є безкоштовним.
ypercubeᵀᴹ

0

Обидва двигуни будуть запускати запит набагато швидше

INDEX(threadid, attach, postid)

Це тому, що це буде "покриває" індекс, і буде працювати практично так само (використовуючи індекс BTree).

Також я скажу, що це неможливо для жодного двигуна на "холодному" сервері:

62510 rows in set (0.13 sec)

Будь ласка, використовуйте SQL_NO_CACHE щоразу, коли виконується таймінги - ми не хочемо, щоб кеш запитів забруднював висновки.

Ще один швидкий підхід (без урахування кешування вводу / виводу):

Використовуйте InnoDB та переходите з PRIMARY KEY (postid)на

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

Причина полягає в тому, що це змусить всі відповідні рядки суміжно, в результаті чого потрібно менше введення / виведення і т.д. INDEX(postid), щоб тримати AUTO_INCREMENTщасливим. Caveat: Це помилка з усіма вторинними клавішами - деякі будуть швидшими, інші - повільнішими.


0

Хоча це не застосовується безпосередньо до @jollyroger, оскільки він вже має правильну настройку, але я отримав значне поліпшення, змінивши innodb_buffer_pool_size70% моєї оперативної пам’яті, як пояснено в Чому myisam повільніше, ніж Innodb

Спочатку MyISAMбуло повільно, але добре. Тоді InnoDBвсе зробило погано, схоже на 100 InnoDBразів повільніше в цьому питанні, і після зміни налаштування потім на 10 разів швидше MyISAM.

Моє налаштування за замовчуванням було на 8 МБ, що далеко не мало.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.