У мене досить дратівлива проблема. Я хочу використовувати 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-боти постійно повзають ці нитки.
