为什么myisam比Innodb慢

时间:2016-06-06 12:29:45

标签: mysql innodb myisam query-performance

有几个Q& A用于"为什么InnoDB(很多)比MyISAM"慢,但我找不到相反的主题。

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

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)

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

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

3 个答案:

答案 0 :(得分:2)

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

详细说明:

“MyISAM更快” - 这是一个老妻子的故事。今天,InnoDB在大多数情况下更快。

假设你有至少4GB的RAM ......

  • 如果全部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'内联'与其他列放在一起。
  • InnoDB将每个blob的大部分或全部放在其他块中。

结论:
MyISAM表中的表扫描花了很多时间踩过奶牛垫; 如果你没有碰到BLOB,那么InnoDB要快得多 当SELECT SUM(x) FROM tbl;上没有索引时,这使得InnoDB成为x的明显赢家。使用INDEX(x),任何引擎都会很快。

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

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

因为BLOB占据了每行的大小,对其他列的调整对性能的影响非常小。

如果您决定使用MyISAM,我会建议使用“并行”表(“垂直分区”)。将BLOB和id放在一个单独的表中。这将有助于MyISAM更接近InnoDB的模型和性能,但会增加代码的复杂性。

对于“点查询”(通过索引查找单行),引擎之间的性能差异不会很大。

你的my.cnf似乎是古董; <{1}}在很长一段时间内都没有必要。

答案 1 :(得分:0)

尝试编辑你的MySQL配置文件,通常是/etc/mysql/my.cnf并使用“巨大的”预设。

# 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

答案 2 :(得分:0)

读取4500条记录肯定是30秒非常慢。假设有足够的空间进行I / O缓存,那么我要尝试的第一件事就是改变字段的顺序;如果这些按照它们被声明的顺序写入表中,则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;

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