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