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_post
tabel ke tabel baru yang dipanggil newbb_innopost
dan mengubahnya ke InnoDB. Tabel saat ini 5,390,146
masing-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_pool
ukuran 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.