为什么 InnoDB 上的简单 SELECT 比 MyISAM 慢 100 倍?

jol*_*ger 36 mysql innodb myisam performance

我有一个很烦人的问题。我想使用 INNODB 作为我的主要数据库引擎并放弃 MyISAM,因为我需要前者来使用 galera-cluster 进行冗余。

我将newbb_post表复制(描述如下)到一个名为的新表newbb_innopost并将其更改为 InnoDB。每个表当前都保存5,390,146条目。

在新启动的数据库上运行这些选择(因此此时不涉及缓存!)数据库产生以下结果(省略完整的输出,请注意我什至不要求数据库对结果进行排序):

SELECT post.postid, post.attach FROM newbb_post AS post WHERE post.threadid = 51506;

.
.
| 5401593 | 0 |
| 5401634 | 0 |
+---------+--------+
62510 行(0.13 秒)
SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506;
.
.
| 5397410 | 0 |
| 5397883 | 0 |
+---------+--------+
62510 行(1 分 22.19 秒)

0.13 秒到 86.19 秒 (!)

我想知道为什么会这样。我确实在 Stackexchange 上阅读了一些涉及 InnoDB 的答案,有些人建议将innodb_buffer_pool大小增加到已安装 RAM 的 80%。这并不能解决问题,即对特定 ID 的初始查询将花费至少 50 倍的时间并停止整个 websever,排队连接和查询数据库。之后缓存/缓冲区可能会启动,但该数据库中有超过 100.000 个线程,因此缓存很可能永远不会保存所有要提供的相关查询。

上面的查询很简单(没有连接),并且使用了所有键:

EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506;
+------+-------------+-------+------+-------------- ----------------------------------+----------+---- -----+-------+--------+-------+
| 身份证 | 选择类型 | 表| 类型 | 可能的密钥| 关键| 密钥长度 | 参考 | 行 | 额外 |
+------+-------------+-------+------+-------------- ----------------------------------+----------+---- -----+-------+--------+-------+
| 1 | 简单 | 发布 | 参考 | threadid,threadid_2,threadid_visible_dateline | 线程ID | 4 | 常量 | 120144 | |
+------+-------------+-------+------+-------------- ----------------------------------+----------+---- -----+-------+--------+-------+

这是 MyISAM 表:

创建表`newbb_post`(
  `postid` int(10) 无符号 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) NOT NULL DEFAULT '',
  `dateline` int(10) unsigned NOT NULL DEFAULT '0',
  `pagetext` 中文本,
  `allowsmilie` smallint(6) NOT NULL DEFAULT '0',
  `showsignature` smallint(6) NOT NULL DEFAULT '0',
  `ipaddress` varchar(15) NOT NULL DEFAULT '',
  `iconid` smallint(5) 无符号 NOT NULL DEFAULT '0',
  `visible` smallint(6) NOT NULL DEFAULT '0',
  `attach` smallint(5) 无符号 NOT NULL DEFAULT '0',
  `infraction` smallint(5) 无符号 NOT NULL DEFAULT '0',
  `reportthreadid` int(10) unsigned NOT NULL DEFAULT '0',
  `importthreadid` bigint(20) NOT NULL DEFAULT '0',
  `importpostid` bigint(20) NOT NULL DEFAULT '0',
  `converted_2_utf8` int(11) 非空,
  `htmlstate` enum('off','on','on_nl2br') NOT NULL DEFAULT 'on_nl2br',
  主键(`postid`),
  KEY `threadid` (`threadid`,`userid`),
  KEY`importpost_index`(`importpostid`),
  KEY`dateline`(`dateline`),
  KEY `threadid_2` (`threadid`,`visible`,`dateline`),
  密钥`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) 无符号 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) NOT NULL DEFAULT '',
  `dateline` int(10) unsigned NOT NULL DEFAULT '0',
  `pagetext` 中文本,
  `allowsmilie` smallint(6) NOT NULL DEFAULT '0',
  `showsignature` smallint(6) NOT NULL DEFAULT '0',
  `ipaddress` varchar(15) NOT NULL DEFAULT '',
  `iconid` smallint(5) 无符号 NOT NULL DEFAULT '0',
  `visible` smallint(6) NOT NULL DEFAULT '0',
  `attach` smallint(5) 无符号 NOT NULL DEFAULT '0',
  `infraction` smallint(5) 无符号 NOT NULL DEFAULT '0',
  `reportthreadid` int(10) unsigned NOT NULL DEFAULT '0',
  `importthreadid` bigint(20) NOT NULL DEFAULT '0',
  `importpostid` bigint(20) NOT NULL DEFAULT '0',
  `converted_2_utf8` int(11) 非空,
  `htmlstate` enum('off','on','on_nl2br') NOT NULL DEFAULT 'on_nl2br',
  主键(`postid`),
  KEY `threadid` (`threadid`,`userid`),
  KEY`importpost_index`(`importpostid`),
  KEY`dateline`(`dateline`),
  KEY `threadid_2` (`threadid`,`visible`,`dateline`),
  密钥`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 内存:

服务器版本:10.0.12-MariaDB-1~trusty-wsrep-log mariadb.org 二进制分发,wsrep_25.10.r4002

如果您需要所有 innodb_ 变量设置,我可以将其附加到这篇文章中。

更新:

我删除了除主索引之外的所有索引,之后结果如下所示:

.
.
| 5402697 | 0 |
| 5402759 | 0 |
+---------+--------+
62510 行(29.74 秒)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506;
+------+-------------+-------+------+-------------- --+------+---------+------+---------+------ +
| 身份证 | 选择类型 | 表| 类型 | 可能的密钥| 关键| 密钥长度 | 参考 | 行 | 额外 |
+------+-------------+-------+------+-------------- --+------+---------+------+---------+------ +
| 1 | 简单 | 发布 | 所有 | 空 | 空 | 空 | 空 | 5909836 | 使用 where |
+------+-------------+-------+------+-------------- --+------+---------+------+---------+------ +
1 行(0.00 秒)

在此之后,我只是将一个索引重新添加到组合中,threadid,结果如下:

.
.
| 5402697 | 0 |
| 5402759 | 0 |
+---------+--------+
62510 行(11.58 秒)
EXPLAIN SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506;
+------+-------------+-------+------+-------------- --+----------+---------+-------+--------+-------+
| 身份证 | 选择类型 | 表| 类型 | 可能的密钥| 关键| 密钥长度 | 参考 | 行 | 额外 |
+------+-------------+-------+------+-------------- --+----------+---------+-------+--------+-------+
| 1 | 简单 | 发布 | 参考 | 线程ID | 线程ID | 4 | 常量 | 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

# 这将传递给所有 m​​ysql 客户端
# 据报道,密码应该用勾号/引号括起来
# 特别是如果它们包含“#”字符...
# 更改socket位置时记得编辑/etc/mysql/debian.cnf。
[客户]
端口 = 3306
socket = /var/run/mysqld/mysqld.sock

# 这里是一些特定程序的条目
# 以下值假设您至少有 32M ram

# 这被正式称为 [safe_mysqld]。目前已解析两个版本。
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
不错 = 0

[mysqld]
#
# * 基本设置
#
用户 = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
端口 = 3306
basedir = /usr
数据目录 = /var/lib/mysql
tmpdir = /tmp
lc_messages_dir = /usr/share/mysql
lc_messages = en_US
跳过外部锁定
#
# 现在不是跳过网络,默认是只监听
# localhost 更兼容且不那么安全。
绑定地址 = 127.0.0.1
#
# * 微调
#
最大连接数 = 100
连接超时 = 5
等待超时 = 600
max_allowed_pa​​cket = 16M
线程缓存大小 = 128
sort_buffer_size = 4M
批量插入缓冲区大小 = 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
并发插入 = 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,TRADITIONAL
#
# * 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_pa​​cket = 16M

[mysql]
#no-auto-rehash # mysql 启动更快,但没有选项卡完成

[isamchk]
key_buffer = 16M

#
# * 重要提示:可以覆盖此文件中的设置的其他设置!
# 文件必须以'.cnf'结尾,否则会被忽略。
#
!includedir /etc/mysql/conf.d/

以及 inno 变量的内容:

MariaDB [(none)]> SHOW VARIABLES LIKE '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 | 指数退避|
| 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_pa​​ges | 开 |
| 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_pa​​ges | 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_pa​​ges | 关闭 |
| 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-20 秒。我确实想指出,关于 threadid 的第一个查询在不到一秒的时间内返回对我来说至关重要(这是一个公告板的主表),因为有超过 60.000 个线程并且 google-bots 不断地爬行这些线程。

Rol*_*DBA 24

您的查询

SELECT post.postid, post.attach FROM newbb_innopost AS post WHERE post.threadid = 51506;
Run Code Online (Sandbox Code Playgroud)

乍一看,该查询应该只涉及表的 1.1597%(5390146 个中的 62510 个)。鉴于threadid 51506的密钥分配,它应该很快。

现实检查

无论您使用哪个版本的 MySQL(Oracle、Percona、MariaDB),它们都无法与一个共同的敌人作战:InnoDB 架构。

InnoDB 架构

集群索引

请记住,每个 threadid 条目都附加了一个主键。这意味着当您从索引中读取时,它必须在ClusteredIndex(内部命名为 gen_clust_index)内进行主键查找。在 ClusteredIndex 中,每个 InnoDB 页面都包含数据和 PRIMARY KEY 索引信息。有关更多信息,请参阅我的帖子Best of MyISAM 和 InnoDB

冗余索引

由于某些索引具有相同的前导列,因此表中有很多混乱。MySQL 和 InnoDB 必须在索引混乱中导航才能到达所需的 BTREE 节点。您应该通过运行以下命令来减少混乱:

ALTER TABLE newbb_innopost
    DROP INDEX threadid,
    DROP INDEX threadid_2,
    DROP INDEX threadid_visible_dateline,
    ADD INDEX threadid_visible_dateline_index (`threadid`,`visible`,`dateline`,`userid`)
;
Run Code Online (Sandbox Code Playgroud)

为什么要剥离这些索引?

  • 前三个索引以threadid开头
  • threadid_2threadid_visible_dateline从相同的三列开始
  • threadid_visible_dateline 不需要 postid,因为它是 PRIMARY KEY 并且它是嵌入的

缓存缓存

InnoDB 缓冲池缓存数据和索引页。MyISAM 只缓存索引页。

仅在这方面,MyISAM 不会浪费时间缓存数据。那是因为它不是为缓存数据而设计的。InnoDB 缓存它接触的每个数据页和索引页(及其祖母)。如果您的 InnoDB 缓冲池太小,您可能会在一个查询中缓存页面、使页面无效和删除页面。

表格布局

您可以通过考虑importthreadid和 来减少行中的一些空间importpostid。您将它们作为 BIGINT。它们在每行的 ClusteredIndex 中占用 16 个字节。

你应该运行这个

SELECT importthreadid,importpostid FROM newbb_innopost PROCEDURE ANALYSE();
Run Code Online (Sandbox Code Playgroud)

这将为给定的数据集推荐这些列应该是什么数据类型。

结论

与 InnoDB 相比,MyISAM 的竞争要小得多,尤其是在缓存领域。

虽然您透露了 RAM ( 32GB)的数量和 MySQL ( Server version: 10.0.12-MariaDB-1~trusty-wsrep-log mariadb.org binary distribution, wsrep_25.10.r4002)的版本,但您还没有透露这个谜题的其他部分

  • InnoDB 设置
  • 核心数
  • 其他设置来自 my.cnf

如果您可以将这些内容添加到问题中,我可以进一步详细说明。

更新 2014-08-28 11:27 EDT

你应该增加线程

innodb_read_io_threads = 64
innodb_write_io_threads = 16
innodb_log_buffer_size = 256M
Run Code Online (Sandbox Code Playgroud)

我会考虑禁用查询缓存(请参阅我最近的帖子为什么默认情况下禁用 query_cache_type 从 MySQL 5.6 开始?

query_cache_size = 0
Run Code Online (Sandbox Code Playgroud)

我会保留缓冲池

innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1
Run Code Online (Sandbox Code Playgroud)

增加清除线程(如果您在多个表上执行 DML)

innodb_purge_threads = 4
Run Code Online (Sandbox Code Playgroud)

试一试 !!!

  • @watery 这是全尺寸图片:http://www.scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing (2认同)

jol*_*ger 6

@RolandMySQLDBA 给出了正确的提示来回答这个问题。问题似乎在于查询,并且要返回结果,必须读取每个字段(以某种方式从数据库中读取)。

我删除了除 之外的所有索引PRIMARY KEY,并插入了这个新索引:

ALTER TABLE newbb_innopost ADD INDEX threadid_visible_dateline_index (threadid,visible,dateline,userid,attach,ipaddress);

链接解释了此处发生的情况(覆盖索引):postid,attach现在可以从键本身提取查询的查询字段。这节省了检查真实数据和使用硬盘的 I/O。

所有查询现在都以 0.00 秒运行.. :)

非常感谢大家的帮助。

编辑:实际的潜在问题没有解决,我只是用这种技术规避了它。InnoDB 在这方面需要一些认真的修复。