为什么 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 需要在读取大小值之前查找每条记录的末尾(我还建议限制这些 vharchar(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
好久没用了。
"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 需要在读取大小值之前查找每条记录的末尾(我还建议限制这些 vharchar(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
好久没用了。