Saya punya masalah yang cukup mengganggu. Saya ingin menggunakan INNODB sebagai mesin database utama saya dan menyerah pada MyISAM karena saya membutuhkan yang pertama untuk menggunakan galera-cluster untuk redundansi.
Saya menyalin (uraian berikut) newbb_posttabel ke tabel baru yang dipanggil newbb_innopostdan mengubahnya ke InnoDB. Tabel saat ini 5,390,146masing-masing menampung entri.
Menjalankan pilihan ini pada database yang baru dimulai (jadi tidak ada caching yang terlibat pada saat ini!) Database menghasilkan hasil berikut (menghilangkan output lengkap, harap dicatat bahwa saya bahkan tidak meminta database untuk mengurutkan hasilnya):
PILIH post.postid, post.attach DARI newbb_post AS post WHERE post.threadid = 51506; . . | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 62510 baris dalam pengaturan (0,13 detik)
PILIH post.postid, post.attach DARI newbb_innopost AS post WHERE post.threadid = 51506; . . | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 62510 baris dalam set (1 mnt 22,19 dtk)
0,13 detik hingga 86,19 detik (!)
Saya bertanya-tanya mengapa ini terjadi. Saya memang membaca beberapa jawaban di Stackexchange yang melibatkan InnoDB dan ada yang menyarankan peningkatan innodb_buffer_poolukuran hingga 80% dari RAM yang dipasang. Ini tidak akan menyelesaikan masalah, bahwa permintaan awal untuk ID tertentu akan memakan waktu setidaknya 50x lebih lama dan menghentikan seluruh websever, mengantri koneksi dan permintaan untuk database. Setelah itu cache / buffer mungkin muncul, tetapi ada lebih dari 100.000 utas dalam database ini, sehingga sangat mungkin bahwa cache tidak akan pernah menahan semua permintaan yang relevan untuk dilayani.
Pertanyaan di atas sederhana (tidak ada yang bergabung), dan semua kunci digunakan:
JELASKAN SELECT post.postid, post.attach DARI newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | id | select_type | meja | ketik | mungkin_kunci | kunci | key_len | ref | baris | Ekstra | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | 1 | SEDERHANA | posting | ref | threadid, threadid_2, threadid_visible_dateline | threadid | 4 | const | 120144 | | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
Ini adalah Tabel MyISAM:
CREATE TABLE `newbb_post` (
`postid` int (10) unsigned NOT NULL AUTO_INCREMENT,
`threadid` int (10) unsigned NOT NULL DEFAULT '0',
`parentid` int (10) unsigned NOT NULL DEFAULT '0',
`username` varchar (100) NOT NULL DEFAULT '',
`userid` int (10) unsigned NOT NULL DEFAULT '0',
`title` varchar (250) BUKAN NULL DEFAULT '',
`dateline` int (10) unsigned NOT NULL DEFAULT '0',
mediumtext `pagetext`,
`allowmilie` smallint (6) NOT NULL DEFAULT '0',
`showsignature` smallint (6) NOT NULL DEFAULT '0',
`ipaddress` varchar (15) BUKAN NULL DEFAULT '',
`iconid` smallint (5) unsigned NOT NULL DEFAULT '0',
`visible` smallint (6) NOT NULL DEFAULT '0',
`attach` smallint (5) unsigned NOT NULL DEFAULT '0',
`pelanggaran` smallint (5) unsigned NOT NULL DEFAULT '0',
`reportthreadid` int (10) unsigned NOT NULL DEFAULT '0',
`importthreadid` bigint (20) NOT NULL DEFAULT '0',
`importpostid` bigint (20) BUKAN NULL DEFAULT '0',
`convert_2_utf8` int (11) TIDAK NULL,
`htmlstate` enum ('off', 'on', 'on_nl2br') BUKAN NULL DEFAULT 'on_nl2br',
KUNCI UTAMA (`postid`),
KUNCI `threadid` (` threadid`, `userid`),
KUNCI `importpost_index` (` importpostid`),
`Dateline` KUNCI (` dateline`),
KUNCI `threadid_2` (` threadid`, `terlihat`,` dateline`),
KUNCI `convert_2_utf8` (` dikonversi_2_utf8`),
KUNCI `threadid_visible_dateline` (` threadid`, `visible`,` dateline`, `userid`,` postid`),
KUNCI `ipaddress` (` ipaddress`),
KUNCI `userid` (` userid`, `parentid`),
`User_date` KUNCI (` userid`, `dateline`)
) ENGINE = MyISAM AUTO_INCREMENT = 5402802 CHARSET DEFAULT = latin1
dan ini adalah Tabel InnoDB (persis sama):
CREATE TABLE `newbb_innopost` (
`postid` int (10) unsigned NOT NULL AUTO_INCREMENT,
`threadid` int (10) unsigned NOT NULL DEFAULT '0',
`parentid` int (10) unsigned NOT NULL DEFAULT '0',
`username` varchar (100) NOT NULL DEFAULT '',
`userid` int (10) unsigned NOT NULL DEFAULT '0',
`title` varchar (250) BUKAN NULL DEFAULT '',
`dateline` int (10) unsigned NOT NULL DEFAULT '0',
mediumtext `pagetext`,
`allowmilie` smallint (6) NOT NULL DEFAULT '0',
`showsignature` smallint (6) NOT NULL DEFAULT '0',
`ipaddress` varchar (15) BUKAN NULL DEFAULT '',
`iconid` smallint (5) unsigned NOT NULL DEFAULT '0',
`visible` smallint (6) NOT NULL DEFAULT '0',
`attach` smallint (5) unsigned NOT NULL DEFAULT '0',
`pelanggaran` smallint (5) unsigned NOT NULL DEFAULT '0',
`reportthreadid` int (10) unsigned NOT NULL DEFAULT '0',
`importthreadid` bigint (20) NOT NULL DEFAULT '0',
`importpostid` bigint (20) BUKAN NULL DEFAULT '0',
`convert_2_utf8` int (11) TIDAK NULL,
`htmlstate` enum ('off', 'on', 'on_nl2br') BUKAN NULL DEFAULT 'on_nl2br',
KUNCI UTAMA (`postid`),
KUNCI `threadid` (` threadid`, `userid`),
KUNCI `importpost_index` (` importpostid`),
`Dateline` KUNCI (` dateline`),
KUNCI `threadid_2` (` threadid`, `terlihat`,` dateline`),
KUNCI `convert_2_utf8` (` dikonversi_2_utf8`),
KUNCI `threadid_visible_dateline` (` threadid`, `visible`,` dateline`, `userid`,` postid`),
KUNCI `ipaddress` (` ipaddress`),
KUNCI `userid` (` userid`, `parentid`),
`User_date` KUNCI (` userid`, `dateline`)
) ENGINE = InnoDB AUTO_INCREMENT = 5402802 CHARSET DEFAULT = latin1
Server, dengan RAM 32GB:
Versi server: 10.0.12-MariaDB-1 ~ trusty-wsrep-log distribusi biner mariadb.org, wsrep_25.10.r4002
Jika Anda memerlukan semua pengaturan variabel innodb_, saya dapat melampirkannya pada posting ini.
Memperbarui:
Saya menjatuhkan SEMUA indeks terpisah dari indeks primer, setelah itu hasilnya tampak seperti ini:
. . | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 62510 baris di atur (29,74 dtk)
JELASKAN SELECT post.postid, post.attach DARI newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | id | select_type | meja | ketik | mungkin_kunci | kunci | key_len | ref | baris | Ekstra | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + | 1 | SEDERHANA | posting | SEMUA | NULL | NULL | NULL | NULL | 5909836 | Menggunakan dimana | + ------ + ------------- + ------- + ------ + ------------- - + ------ + --------- + ------ + --------- + ------------- + 1 baris dalam set (0,00 dtk)
Setelah ini saya baru saja menambahkan satu indeks kembali ke mix, threadid, hasilnya adalah sebagai berikut:
. . | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 62510 baris di atur (11,58 detik)
JELASKAN SELECT post.postid, post.attach DARI newbb_innopost AS post WHERE post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | id | select_type | meja | ketik | mungkin_kunci | kunci | key_len | ref | baris | Ekstra | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + | 1 | SEDERHANA | posting | ref | threadid | threadid | 4 | const | 124622 | | + ------ + ------------- + ------- + ------ + ------------- - + ---------- + --------- + ------- + -------- + ------- + 1 baris dalam set (0,00 dtk)
Anehnya, tanpa indeks yang relevan, pemindaian lengkap hanya membutuhkan waktu 29 detik dibandingkan dengan 88 detik menggunakan indeks (!).
Dengan hanya satu indeks yang disesuaikan dengan sempurna, proses ini masih memerlukan waktu 11 detik - masih terlalu lambat untuk penggunaan di dunia nyata.
Pembaruan 2:
Saya mengatur MySQL (5.5.38-0ubuntu0.14.04.1 (Ubuntu)) di server lain dengan konfigurasi perangkat keras yang sama persis dan database / tabel yang sama persis.
Hasilnya hampir sama, pertama Tabel MyISAM:
. . | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 62510 baris dalam set (0,14 detik)
Dan ini adalah hasil dari tabel InnoDB
. . | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 62510 baris dalam set (1 mnt 17,63 dtk)
UPDATE 3: isi my.cnf
# File konfigurasi server database MariaDB.
#
# Anda dapat menyalin file ini ke salah satu dari:
# - "/etc/mysql/my.cnf" untuk mengatur opsi global,
# - "~ / .my.cnf" untuk mengatur opsi spesifik pengguna.
#
# Seseorang dapat menggunakan semua opsi panjang yang didukung oleh program.
# Jalankan program dengan --help untuk mendapatkan daftar opsi yang tersedia dan dengan
# --print-defaults untuk melihat yang benar-benar dimengerti dan digunakan.
#
# Untuk penjelasan, lihat
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
# Ini akan diteruskan ke semua klien mysql
# Telah dilaporkan bahwa kata sandi harus diapit dengan tanda centang / tanda kutip
# terutama jika mengandung "#" karakter ...
# Ingatlah untuk mengedit /etc/mysql/debian.cnf saat mengubah lokasi soket.
[klien]
port = 3306
socket = /var/run/mysqld/mysqld.sock
# Ini adalah entri untuk beberapa program tertentu
# Nilai-nilai berikut menganggap Anda memiliki setidaknya 32 juta ram
# Ini secara resmi dikenal sebagai [safe_mysqld]. Kedua versi saat ini diuraikan.
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
bagus = 0
[mysqld]
#
# * Pengaturan dasar
#
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 = en_US
skip-external-locking
#
# Alih-alih melewatkan jaringan, default sekarang adalah hanya mendengarkan
# localhost yang lebih kompatibel dan tidak kalah aman.
bind-address = 127.0.0.1
#
# * Mencari setelan
#
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 = 16 juta
tmp_table_size = 32M
max_heap_table_size = 32M
#
# * MyISAM
#
# Ini menggantikan skrip startup dan memeriksa tabel MyISAM jika diperlukan
# pertama kali mereka disentuh. Jika terjadi kesalahan, buat salinan dan coba perbaikan.
myisam_recover = CADANGAN
key_buffer_size = 128M
# 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
#
# * Konfigurasi Cache Kueri
#
# Cache hanya set hasil yang kecil, sehingga kami dapat memuat lebih banyak dalam cache kueri.
query_cache_limit = 128K
query_cache_size = 64M
# untuk pengaturan penulisan yang lebih intensif, atur PERMINTAAN atau MATI
#query_cache_type = PERMINTAAN
#
# * Penebangan dan Replikasi
#
# Kedua lokasi diputar oleh cronjob.
# Perlu diketahui bahwa jenis log ini adalah pembunuh kinerja.
# Pada 5.1 Anda dapat mengaktifkan log saat runtime!
#general_log_file = /var/log/mysql/mysql.log
#general_log = 1
#
# Kesalahan logging masuk ke syslog karena /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
#
Kami ingin tahu tentang kesalahan jaringan dan semacamnya
log_warnings = 2
#
# Aktifkan log kueri lambat untuk melihat kueri dengan durasi sangat panjang
#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-using-indexes
#log_slow_admin_statements
#
# Hal berikut ini dapat digunakan untuk memutar ulang log cadangan atau untuk replikasi.
# note: jika Anda menyiapkan budak replikasi, lihat README.Debian tentang
# pengaturan lain yang mungkin perlu Anda ubah.
# 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
# tidak hebat untuk kinerja, tetapi lebih aman
#sync_binlog = 1
expire_logs_days = 10
max_binlog_size = 100M
# budak
#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
#read_only
#
# Jika aplikasi mendukungnya, sql_mode yang lebih ketat ini mencegah beberapa
# kesalahan seperti memasukkan tanggal yang tidak valid, dll.
#sql_mode = NO_ENGINE_SUBSTITUTION, TRADITIONAL
#
# * InnoDB
#
# InnoDB diaktifkan secara default dengan datafile 10MB di / var / lib / mysql /.
# Baca manual untuk opsi terkait InnoDB lainnya. Ada banyak!
default_storage_engine = InnoDB
# Anda tidak bisa hanya mengubah ukuran file log, memerlukan prosedur khusus
#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
#
# * Fitur keamanan
#
# Baca manual juga, jika Anda ingin chroot!
# chroot = / var / lib / mysql /
#
# Untuk menghasilkan sertifikat SSL, saya merekomendasikan OpenSSL GUI "tinyca".
#
# ssl-ca = / etc / mysql / cacert.pem
# ssl-cert = / etc / mysql / server-cert.pem
# ssl-key = / etc / mysql / server-key.pem
[mysqldump]
cepat
nama-kutipan
max_allowed_packet = 16M
[mysql]
# no-auto-rehash # lebih cepat memulai mysql tetapi tidak ada penyelesaian tab
[isamchk]
key_buffer = 16 juta
#
# * PENTING: Pengaturan tambahan yang dapat menggantikan yang dari file ini!
# File harus diakhiri dengan '.cnf', jika tidak mereka akan diabaikan.
#
! Includedir /etc/mysql/conf.d/
Dan isi dari variabel inno:
MariaDB [(tidak ada)]> TAMPILKAN VARIABEL SEPERTI 'inno%'; + ------------------------------------------- + ----- ------------------- + | Variable_name | Nilai | + ------------------------------------------- + ----- ------------------- + | 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 | OFF | | innodb_api_enable_binlog | OFF | | innodb_api_enable_mdl | OFF | | innodb_api_trx_level | 0 | | innodb_autoextend_increment | 64 | | innodb_autoinc_lock_mode | 1 | | innodb_buffer_pool_dump_at_shutdown | OFF | | innodb_buffer_pool_dump_now | OFF | | innodb_buffer_pool_filename | ib_buffer_pool | | innodb_buffer_pool_inances | 8 | | innodb_buffer_pool_load_abort | OFF | | innodb_buffer_pool_load_at_startup | OFF | | 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 | semua | | 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_action | menegaskan | | 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 | Antelope | | innodb_file_format_check | ON | | innodb_file_format_max | Antelope | | 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_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 | OFF | | 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 | OFF | | 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 baris diatur (0,02 dtk)
Jumlah inti mesin adalah 8, ini a
Intel(R) Xeon(R) CPU E3-1246 v3 @ 3.50GHz per /proc/cpuinfo
Satu catatan terakhir: Jalankan kueri dengan indeks yang disarankan oleh RolandoMYSQLDBA, dan kueri masing-masing memakan waktu sekitar 11-20. Saya ingin menunjukkan bahwa sangat penting bagi saya (ini adalah tabel utama dari papan buletin) bahwa permintaan pertama tentang pengembalian threadid dalam waktu kurang dari satu detik, karena ada lebih dari 60.000 utas dan google-bot terus merangkak utas ini.
