我有一个很烦人的问题。我想使用INNODB作为我的主要数据库引擎,而放弃MyISAM,因为我需要前者使用galera-cluster来实现冗余。
我将newbb_post
表复制(描述如下)到一个名为的新表中,newbb_innopost
并将其更改为InnoDB。这些表当前5,390,146
每个都有条目。
在新启动的数据库上运行这些选择(因此此时不涉及缓存!),该数据库会产生以下结果(省略完整的输出,请注意,我什至不要求数据库对结果进行排序):
从newbb_post中选择post.postid,post.attach作为post,而post.threadid = 51506; 。 。 | 5401593 | 0 | | 5401634 | 0 | + --------- + -------- + 设置62510行(0.13秒)
从newbb_innopost中选择post.postid,post.attach作为post,而post.threadid = 51506; 。 。 | 5397410 | 0 | | 5397883 | 0 | + --------- + -------- + 设置62510行(1分22.19秒)
0.13秒至86.19秒(!)
我想知道为什么会这样。我确实在这里阅读了有关InnoDB的Stackexchange的一些答案,并且有人建议将innodb_buffer_pool
大小增加到已安装RAM的80%。这不会解决问题,对特定ID的初始查询将至少花费50倍以上的时间,并使整个Web服务器停滞不前,从而对数据库进行连接和查询。之后可能会启动缓存/缓冲区,但是此数据库中有超过100.000个线程,因此很有可能缓存将永远无法容纳要服务的所有相关查询。
上面的查询很简单(没有连接),并且使用了所有键:
从newbb_innopost解释选择post.postid,post.attach作为post在哪里post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | id | select_type | 桌子| 类型 可能的钥匙| 关键 key_len | 参考| 行| 额外| + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- + | 1 | 简单 发布| 参考| threadid,threadid_2,threadid_visible_dateline | threadid | 4 | const | 120144 | | + ------ + ------------- + ------- + ------ + ------------- ---------------------------------- + ---------- + ---- ----- + ------- + -------- + ------- +
这是MyISAM表:
创建表`newbb_post`( `postid` int(10)unsigned NOT NULL AUTO_INCREMENT, `threadid` int(10)unsigned NOT NULL默认值为'0', `parentid` int(10)unsigned NOT NULL默认值为'0', `username` varchar(100)NOT NULL DEFAULT'', `userid` int(10)unsigned NOT NULL DEFAULT'0', `title` varchar(250)NOT NULL DEFAULT'', dateline int(10)unsigned NOT NULL默认值'0', `pagetext`中文字, `allowsmilie` smallint(6)NOT NULL缺省'0', `showsignature`smallint(6)NOT NULL默认为'0', ipaddress varchar(15)非空默认值'', `iconid` smallint(5)unsigned NOT NULL默认值为'0', `visible` smallint(6)NOT NULL缺省'0', `attach`smallint(5)unsigned NOT NULL缺省'0', `infraction` smallint(5)unsigned NOT NULL DEFAULT'0', `reportthreadid` int(10)unsigned NOT NULL缺省'0', `importthreadid` bigint(20)NOT NULL缺省'0', `importpostid` bigint(20)NOT NULL缺省'0', `converted_2_utf8` int(11)NOT NULL, htmlstate` enum('off','on','on_nl2br')NOT NULL默认'on_nl2br', 主键(`postid`), KEY`threadid`(`threadid`,`userid`), KEY`importpost_index`(`importpostid`), KEY`dateline`(`dateline`), KEY`threadid_2`(`threadid`,`visible`,`dateline`), KEY`converted_2_utf8`(`converted_2_utf8`), KEY`threadid_visible_dateline`(`threadid`,`visible`,`dateline`,`userid`,`postid`), KEY`ipaddress`(`ipaddress`), KEY`userid`(`userid`,`parentid`), KEY`user_date`(`userid`,`dateline`) )ENGINE = MyISAM AUTO_INCREMENT = 5402802 DEFAULT CHARSET = latin1
这是InnoDB表(完全相同):
创建表`newbb_innopost`( `postid` int(10)unsigned NOT NULL AUTO_INCREMENT, `threadid` int(10)unsigned NOT NULL默认值为'0', `parentid` int(10)unsigned NOT NULL默认值为'0', `username` varchar(100)NOT NULL DEFAULT'', `userid` int(10)unsigned NOT NULL DEFAULT'0', `title` varchar(250)NOT NULL DEFAULT'', dateline int(10)unsigned NOT NULL默认值'0', `pagetext`中文字, `allowsmilie` smallint(6)NOT NULL缺省'0', `showsignature`smallint(6)NOT NULL默认为'0', ipaddress varchar(15)非空默认值'', `iconid` smallint(5)unsigned NOT NULL默认值为'0', `visible` smallint(6)NOT NULL缺省'0', `attach`smallint(5)unsigned NOT NULL缺省'0', `infraction` smallint(5)unsigned NOT NULL DEFAULT'0', `reportthreadid` int(10)unsigned NOT NULL缺省'0', `importthreadid` bigint(20)NOT NULL缺省'0', `importpostid` bigint(20)NOT NULL缺省'0', `converted_2_utf8` int(11)NOT NULL, htmlstate` enum('off','on','on_nl2br')NOT NULL默认'on_nl2br', 主键(`postid`), KEY`threadid`(`threadid`,`userid`), KEY`importpost_index`(`importpostid`), KEY`dateline`(`dateline`), KEY`threadid_2`(`threadid`,`visible`,`dateline`), KEY`converted_2_utf8`(`converted_2_utf8`), KEY`threadid_visible_dateline`(`threadid`,`visible`,`dateline`,`userid`,`postid`), KEY`ipaddress`(`ipaddress`), KEY`userid`(`userid`,`parentid`), KEY`user_date`(`userid`,`dateline`) )ENGINE = InnoDB AUTO_INCREMENT = 5402802 DEFAULT CHARSET = latin1
服务器,具有32GB RAM:
服务器版本:10.0.12-MariaDB-1〜trusty-wsrep-log mariadb.org二进制分发版,wsrep_25.10.r4002
如果您需要所有innodb_变量设置,我可以将其附加到这篇文章。
更新:
我将所有索引与主索引分开,之后的结果如下所示:
。 。 | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 设置62510行(29.74秒)
从newbb_innopost解释选择post.postid,post.attach作为post在哪里post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- -+ ------ + --------- + ------ + --------- + ------------- + | id | select_type | 桌子| 类型 可能的钥匙| 关键 key_len | 参考| 行| 额外| + ------ + ------------- + ------- + ------ + ------------- -+ ------ + --------- + ------ + --------- + ------------- + | 1 | 简单 发布| 全部| NULL | NULL | NULL | NULL | 5909836 | 在哪里使用 + ------ + ------------- + ------- + ------ + ------------- -+ ------ + --------- + ------ + --------- + ------------- + 设置1行(0.00秒)
在此之后,我将一个索引重新添加到混合中,即threadid,结果如下:
。 。 | 5402697 | 0 | | 5402759 | 0 | + --------- + -------- + 设置62510行(11.58秒)
从newbb_innopost解释选择post.postid,post.attach作为post在哪里post.threadid = 51506; + ------ + ------------- + ------- + ------ + ------------- -+ ---------- + --------- + ------- + -------- + ------- + | id | select_type | 桌子| 类型 可能的钥匙| 关键 key_len | 参考| 行| 额外| + ------ + ------------- + ------- + ------ + ------------- -+ ---------- + --------- + ------- + -------- + ------- + | 1 | 简单 发布| 参考| threadid | threadid | 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-defaults可以查看它实际理解和使用的内容。 # #有关说明,请参阅 #http://dev.mysql.com/doc/mysql/en/server-system-variables.html #这将传递给所有mysql客户端 #据报导,密码应用勾号/引号引起来 #特别是如果它们包含“#”字符... #记住在更改套接字位置时编辑/etc/mysql/debian.cnf。 [客户] 端口= 3306 套接字= /var/run/mysqld/mysqld.sock #这是一些特定程序的条目 #以下值假设您的RAM至少为32M #这被正式称为[safe_mysqld]。这两个版本当前都已解析。 [mysqld_safe] 套接字= /var/run/mysqld/mysqld.sock 好= 0 [mysqld] # # * 基本设置 # 用户= MySQL pid文件= /var/run/mysqld/mysqld.pid 套接字= /var/run/mysqld/mysqld.sock 端口= 3306 basedir = / usr datadir = / var / lib / mysql tmpdir = / tmp lc_messages_dir = / usr / share / mysql lc_messages = zh_CN 跳过外部锁定 # #现在默认不监听网络,而不是跳过网络 #本地主机,兼容性更高,安全性也更高。 绑定地址= 127.0.0.1 # # * 微调 # 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 = 16M tmp_table_size = 32M max_heap_table_size = 32M # #* MyISAM # #这将替换启动脚本并在需要时检查MyISAM表 #第一次触摸它们。如果出错,请进行复制并尝试维修。 myisam_recover =备份 key_buffer_size = 128M #open-files-limit = 2000 table_open_cache = 400 myisam_sort_buffer_size = 512M parallel_insert = 2 read_buffer_size = 2M read_rnd_buffer_size = 1M # #*查询缓存配置 # #仅缓存微小的结果集,因此我们可以在查询缓存中容纳更多结果集。 query_cache_limit = 128K query_cache_size = 64M #用于更密集的写入设置,设置为DEMAND或OFF #query_cache_type =需求 # #*记录和复制 # #两个位置都被cronjob旋转。 #请注意,此日志类型是性能杀手。 #从5.1开始,您可以在运行时启用日志! #general_log_file = /var/log/mysql/mysql.log #general_log = 1 # #由于/etc/mysql/conf.d/mysqld_safe_syslog.cnf,错误日志记录进入syslog。 # #我们确实想了解网络错误等 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-using-indexes #log_slow_admin_statements # #以下内容可用于轻松重放备份日志或进行复制。 #注意:如果要设置复制从属,请参阅README.Debian, #您可能需要更改的其他设置。 #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 #不是为了提高性能而是为了更安全 #sync_binlog = 1 expire_logs_days = 10 max_binlog_size = 100M #奴隶 #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默认情况下在/ var / lib / mysql /中具有10MB数据文件启用。 #阅读手册,了解更多与InnoDB相关的选项。有许多! default_storage_engine = InnoDB #您不能只更改日志文件的大小,需要特殊的过程 #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 # #*安全功能 # #如果需要chroot,也请阅读手册! #chroot = / var / lib / mysql / # #为了生成SSL证书,我建议使用OpenSSL GUI“ 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 = 16M [mysql] #no-auto-rehash#更快地启动mysql,但没有制表符完成 [isamchk] key_buffer = 16M # #*重要:其他设置可以覆盖此文件中的设置! #文件必须以'.cnf'结尾,否则将被忽略。 # !includedir /etc/mysql/conf.d/
以及inno变量的内容:
MariaDB [(无)]>显示变量,例如'inno%'; + ------------------------------------------- + ----- ------------------- + | 变量名| 价值| + ------------------------------------------- + ----- ------------------- + | innodb_adaptive_flushing | 开| | innodb_adaptive_flushing_lwm | 10 | | innodb_adaptive_hash_index | 开| | 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_instances | 8 | | innodb_buffer_pool_load_abort | 关闭| | innodb_buffer_pool_load_at_startup | 关闭| | innodb_buffer_pool_load_now | 关闭| | innodb_buffer_pool_populate | 关闭| | innodb_buffer_pool_size | 21474836480 | | innodb_change_buffer_max_size | 25 | | innodb_change_buffering | 全部| | innodb_checksum_algorithm | innodb | | innodb_checksums | 开| | innodb_cleaner_lsn_age_factor | high_checkpoint | | innodb_cmp_per_index_enabled | 关闭| | 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 | 断言 | innodb_data_file_path | ibdata1:12M:autoextend | | innodb_data_home_dir | | | innodb_disable_sort_file_cache | 关闭| | innodb_doublewrite | 开| | innodb_empty_free_list_algorithm | 退让| | innodb_fake_changes | 关闭| | innodb_fast_shutdown | 1 | | innodb_file_format | 羚羊| | innodb_file_format_check | 开| | innodb_file_format_max | 羚羊| | innodb_file_per_table | 开| | 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 | 关闭| | innodb_force_recovery | 0 | | innodb_foreground_preflush | exponential_backoff | | innodb_ft_aux_table | | | innodb_ft_cache_size | 8000000 | | innodb_ft_enable_diag_print | 关闭| | innodb_ft_enable_stopword | 开| | 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 | 关闭| | innodb_lock_wait_timeout | 50 | | innodb_locking_fake_changes | 开| | innodb_locks_unsafe_for_binlog | 关闭| | innodb_log_arch_dir | ./ | | innodb_log_arch_expire_sec | 0 | | innodb_log_archive | 关闭| | innodb_log_block_size | 512 | | innodb_log_buffer_size | 8388608 | | innodb_log_checksum_algorithm | innodb | | innodb_log_compressed_pages | 开| | 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 | 关闭| | innodb_purge_batch_size | 300 | | innodb_purge_threads | 1 | | innodb_random_read_ahead | 关闭| | innodb_read_ahead_threshold | 56 | | innodb_read_io_threads | 4 | | innodb_read_only | 关闭| | innodb_replication_delay | 0 | | innodb_rollback_on_timeout | 关闭| | 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 | 开| | innodb_stats_method | nulls_equal | | innodb_stats_on_metadata | 关闭| | innodb_stats_persistent | 开| | innodb_stats_persistent_sample_pages | 20 | | innodb_stats_sample_pages | 8 | | innodb_stats_transient_sample_pages | 8 | | innodb_status_output | 关闭| | innodb_status_output_locks | 关闭| | innodb_strict_mode | 关闭| | innodb_support_xa | 开| | innodb_sync_array_size | 1 | | innodb_sync_spin_loops | 30 | | innodb_table_locks | 开| | innodb_thread_concurrency | 0 | | innodb_thread_sleep_delay | 10000 | | innodb_track_changed_pages | 关闭| | innodb_undo_directory | 。| | innodb_undo_logs | 128 | | innodb_undo_tablespaces | 0 | | innodb_use_atomic_writes | 关闭| | innodb_use_fallocate | 关闭| | innodb_use_global_flush_log_at_trx_commit | 开| | innodb_use_native_aio | 开| | innodb_use_stacktrace | 关闭| | innodb_use_sys_malloc | 开| | 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。我确实要指出,对我而言(这是公告板的主表),至关重要的是,有关线程ID的第一个查询在不到一秒钟的时间内返回,因为有超过60.000线程并且Google-bot不断爬行这些线程。