为什么 myisam 比 Innodb 慢

Why is myisam slower than Innodb

"Why is InnoDB (much) slower than MyISAM"有几个问答,但是我找不到相反的话题。

所以我有一个 table 定义为 InnoDB,我将文件内容存储在一个 blob 字段中。因为通常应该使用 MyISAM,所以我切换了 table。这是它的结构:

CREATE TABLE `liv_fx_files_files` (
  `fid` int(11) NOT NULL AUTO_INCREMENT,
  `filedata` longblob NOT NULL,
  `filetype` varchar(255) NOT NULL,
  `filename` varchar(255) NOT NULL,
  `filesize` int(11) NOT NULL,
  `context` varchar(1) NOT NULL DEFAULT '',
  `saveuser` varchar(32) NOT NULL,
  `savetime` int(11) NOT NULL,
  `_state` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`fid`),
  KEY `_state` (`_state`)
) ENGINE=MyISAM AUTO_INCREMENT=4550 DEFAULT CHARSET=utf8;

目前存储了4549条记录(filedata从0到48M,所有文件加起来大约6G。

因此,每当我需要知道当前的总文件大小时,我都会发出查询

SELECT SUM(filesize) FROM liv_fx_files_files;

问题是,自从我从 InnoDB 切换到 MyISAM 之后,这个简单的查询持续了很长时间(大约 30 秒或更长),而在 InnoDB 上,它在不到一秒的时间内完成。

但是聚合并不是唯一非常慢的查询;几乎是每个查询。

我想我可以通过采用配置(目前针对 InnoDB(仅)使用进行了优化)来修复它,但不知道要调整哪些设置。有人可以给我提示吗?

current mysql server config (SHOW VARIABLES as csv)

针对两种 table 类型(均包含完全相同的数据并具有相同的定义)触发的另一个查询的示例。所有其他测试的查询行为相同,比如 运行 比 MyISAM table 比 InnoDB 长得多!

SELECT sql_no_cache `fxfilefile`.`filename` AS `filename` FROM `myisamtable`|`innodbtable` AS `fxfilefile` WHERE `fxfilefile`.`filename` LIKE '%foo%';

尝试编辑您的 MySQL 配置文件,通常是 /etc/mysql/my.cnf 并使用 "huge" 预设。

# The MySQL server
[mysqld]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock
skip-locking
set-variable    = key_buffer=384M
set-variable    = max_allowed_packet=1M
set-variable    = table_cache=512
set-variable    = sort_buffer=2M
set-variable    = record_buffer=2M
set-variable    = thread_cache=8
# Try number of CPU's*2 for thread_concurrency
set-variable    = thread_concurrency=8
set-variable    = myisam_sort_buffer_size=64M

当然30秒读取4500条记录很慢。假设 I/O 缓存有足够的空间,那么我首先要尝试的是更改字段的顺序;如果这些按照声明的顺序写入 table,则 DBMS 需要在读取大小值之前查找每条记录的末尾(我还建议限制这些 vha​​rchar(255) 列的大小,并且 varhar(1) NOT NULL 应该是 CHAR)。

CREATE TABLE `liv_fx_files_files2` (
  `fid` int(11) NOT NULL AUTO_INCREMENT,
  `filesize` int(11) NOT NULL,
  `context` char(1) NOT NULL DEFAULT '',
  `saveuser` varchar(32) NOT NULL,
  `savetime` int(11) NOT NULL,
  `_state` int(11) NOT NULL DEFAULT '0',
  `filetype` varchar(255) NOT NULL,
  `filename` varchar(255) NOT NULL,
  `filedata` longblob NOT NULL,
  PRIMARY KEY (`fid`),
  KEY `_state` (`_state`)
) ENGINE=MyISAM AUTO_INCREMENT=4550 DEFAULT CHARSET=utf8;

INSERT INTO liv_fx_files_files2
(fid, filesize, context, saveuser, savetime, _state, filetype, filename, filedata)
SELECT fid, filesize, context, saveuser, savetime, _state, filetype, filename, filedata
FROM liv_fx_files_files;

但理想情况下,我会将数据和元数据拆分为单独的 tables。

执行摘要:使用 InnoDB,并相应地更改 my.cnf 设置。

详情:

"MyISAM is faster" -- 这是一个老太太的故事。如今,InnoDB 在 大多数 情况下速度更快。

假设您至少有 4GB 内存...

  • 如果全部是MyISAM,key_buffer_size应该是RAM的20%左右; innodb_buffer_pool_size 应为 0。
  • 如果是全 InnoDB,key_buffer_size 应该只有 20MB; innodb_buffer_pool_size 应该是 RAM 的 70% 左右。
  • 如果是混合物,请在两者之间做一些事情。 More discussion.

让我们看看两个引擎处理事情的方式有何不同。

  • MyISAM 将整个 BLOB 'inline' 与其他列放在一起。
  • InnoDB 将每个 blob 的大部分或全部放在其他块中。

结论:
MyISAM table 中的 table 扫描会花费大量时间跨过牛田; InnoDB 快得多 如果 你不碰 BLOB.
x 上没有索引时,这使得 InnoDB 成为 SELECT SUM(x) FROM tbl; 的明显赢家。使用 INDEX(x),任何一个引擎都会很快。

由于 BLOB 是内联的,如果您更新 table 中的记录,MyISAM 会出现碎片问题; InnoDB 的碎片要少得多。这会影响所有操作,使 InnoDB 再次成为赢家。

CREATE TABLE 中列的顺序对任一引擎的性能都没有影响。

因为 BLOB 决定了每一行的大小,所以对其他列的调整对性能的影响很小。

如果您决定使用 MyISAM,我会推荐 'parallel' table ('vertical partitioning')。将 BLOB 和其中的 id 放在一个单独的 table 中。这将有助于 MyISAM 更接近 InnoDB 的模型和性能,但会增加代码的复杂性。

对于"point queries"(通过索引查找单行),引擎之间的性能不会有太大差异。

你的my.cnf看起来很古色古香; set-variable 好久没用了。