Mysql InnoDB插入速度非常慢,速度也越来越慢
最近,我将我的项目表切换到InnoDB(认为有这种关系是件好事)。我使用一个PHP脚本一次索引大约500个产品 存储word/ids关联的表:Mysql InnoDB插入速度非常慢,速度也越来越慢,mysql,performance,innodb,Mysql,Performance,Innodb,最近,我将我的项目表切换到InnoDB(认为有这种关系是件好事)。我使用一个PHP脚本一次索引大约500个产品 存储word/ids关联的表: CREATE TABLE `windex` ( `word` varchar(64) NOT NULL, `wid` int(10) unsigned NOT NULL AUTO_INCREMENT, `count` int(11) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`wid`),
CREATE TABLE `windex` (
`word` varchar(64) NOT NULL,
`wid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`count` int(11) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`wid`),
UNIQUE KEY `word` (`word`)
) ENGINE=InnoDB AUTO_INCREMENT=324551 DEFAULT CHARSET=latin1
另一个表存储产品id/单词id关联:
CREATE TABLE `indx_0` (
`wid` int(7) unsigned NOT NULL,
`pid` int(7) unsigned NOT NULL,
UNIQUE KEY `wid` (`wid`,`pid`),
KEY `pid` (`pid`),
CONSTRAINT `indx_0_ibfk_1` FOREIGN KEY (`wid`) REFERENCES `windex` (`wid`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `indx_0_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `product` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
该脚本使用MyISAM进行了测试,它索引产品的速度相对较快(比InnoDB快得多)。第一次在InnoDB中运行时速度慢得离谱,但在将更多值嵌套在一起之后,我最终将速度提高了很多(但还不够)
我认为innodb在这种情况下会更快,因为有行级锁,但事实并非如此
我构造了一个如下所示的查询:
SELECT
title,keywords,upc,...
FROM product
WHERE indexed = 0
LIMIT 500
我创建一个循环并用需要添加到windex的所有单词和需要添加到indx_0的所有单词id/产品id对填充一个数组
因为每当我执行因重复值而失败的“替换到”或“插入忽略到”时,innodb会不断增加我的自动增量值,所以我需要确保我添加的值不存在。为此,我首先使用如下查询选择所有存在的值:
SELECT wid,word
FROM windex
WHERE
word = "someword1" or word = "someword2" or word = "someword3" ... ...
然后我根据已有的结果过滤掉我的数组,这样我添加的所有新词都是100%新的
这大约占整个执行时间的20%。另外80%用于将成对值添加到indx_0中,对于indx_0,还有更多的值
这是我得到的一个例子
0.4806秒选择产品。(总共0.4807秒)。0.0319秒收集500个项目。(总共0.5126秒)。
5.2396秒,选择windex值进行比较。(总共5.7836秒)。
1.8986秒更新计数。(总共7.6822秒)。
0.0641秒添加832条windex记录。(总共7.7464秒)。
17.2725秒添加3435个pid/wid对的索引。(总共25.7752秒)。
操作耗时26.07秒,对500种产品进行了索引 3435对都在一个查询中执行,例如:
INSERT INTO indx_0(pid,wid)
VALUES (1,4),(3,9),(9,2)... ... ...
在我的例子中,为什么InnoDB比MyISAM慢得多?InnoDB提供了比MyISAM更复杂的密钥结构(
外键),并且在InnoDB中重新生成密钥的速度非常慢。您应该将所有update/insert语句封装到一个事务中(在InnoDB中,这些语句实际上相当快,曾经我在InnoDB表上有大约30000个insert查询,其中包含2个索引,大约需要30分钟,曾经我将每10000个insert封装到BEGIN TRANSACTION
和COMMIT
中,不到2分钟)
我建议使用:
开始交易;
选择。。。从产品;
更新。。。;
插入。。。;
插入。。。;
插入。。。;
犯罪
这将导致InnoDB只刷新索引一次,而不是几百次
让我知道它是否有效我也遇到了类似的问题,而且InnoDB似乎默认启用了InnoDB_flush_log_at_trx_commit,它会刷新硬盘日志文件上的每个插入/更新查询。硬盘的写入速度是此过程的瓶颈
因此,请尝试修改您的mysql配置文件
`innodb_flush_log_at_trx_commit = 0`
重新启动mysql服务
我在插入时体验了大约x100的加速。单词索引的想法是为了创建某种搜索功能吗?如果是这样的话,那么看看真正的搜索引擎,比如solr或mysql全文搜索。我相信这肯定会带来一些进步。我也有类似的问题,维克托。看来这会管用的。谢谢-UdayI在一个光标中遇到了一个问题,这个问题已经解决了(从90秒到0.9秒!)慢慢地,我在学习需要什么InnoDB@Vyktor,关于“我在开始事务
和提交
中每插入10000次,所用时间不到2分钟”,为什么要分成10k批?为什么不在一个事务中包含所有语句?@Pacerier更容易恢复,一般来说,我尽量避免真正大的事务,这样我就不会在内部表锁上遇到麻烦了…@Vyktor,现在我不确定我是否理解您的意思,当我们正确执行批插入时,该事务肯定是唯一正在运行的。。。。。。另外,您所说的“更容易恢复”是什么意思?请注意,应用此选项会失去事务安全性。。。如果您在告诉客户机它已经完成之后,但在它真正写入磁盘之前,失去了电源,则意味着它将永远失去电源。