InnoDB插入速度非常慢,速度慢

nic*_*ick 10 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`),
 UNIQUE KEY `word` (`word`)
) ENGINE=InnoDB AUTO_INCREMENT=324551 DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)

另一个表存储产品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
Run Code Online (Sandbox Code Playgroud)

该脚本使用MyISAM进行测试,它可以相对快速地对产品进行索引(比InnoDB快得多).第一次在InnoDB中运行它是非常缓慢的但是在将更多的值嵌套在一起之后我最终加速了很多(但还不够).

我认为innodb对于这种类型的东西要快得多,因为行级别的锁定但事实并非如此.

我构造一个看起来像这样的查询:

SELECT
title,keywords,upc,...
FROM product
WHERE indexed = 0
LIMIT 500
Run Code Online (Sandbox Code Playgroud)

我创建一个循环并填充一个数组,其中包含需要添加到windex的所有单词以及需要添加到indx_0的所有单词id/product id对.

因为innodb不断增加我的自动增量值,每当我执行"REPLACE INTO"或"INSERT IGNORE INTO"由于重复值而失败时,我需要确保我添加的值不存在.为此,我首先使用如下查询选择所有存在的值:

SELECT wid,word
FROM windex
WHERE
word = "someword1" or word = "someword2" or word = "someword3" ... ...
Run Code Online (Sandbox Code Playgroud)

然后我根据存在的结果筛选出我的数组,这样我添加的所有新单词都是100%新的.

这大约占总执行时间的20%.另外80%用于将对值添加到indx_0中,其中有更多值.

这是我得到的一个例子.

0.4806秒选择产品.(总共0.4807秒).
收集500件物品0.0319秒.(总共0.5126秒).
5.2396秒选择windex值进行比较.(总共5.7836秒).
1.8986秒更新计数.(总共7.6822秒).
添加832个windex记录0.0641秒.(总共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)... ... ...
Run Code Online (Sandbox Code Playgroud)

在我的情况下,为什么InnoDB比MyISAM慢得多?

Vyk*_*tor 18

InnoDB提供比MyIsam(FOREIGN KEYS)更复杂的键结构,并且InnoDB中的再生键非常慢.你应该附上所有更新/插入语句到一个事务(这些实际上是相当快的InnoDB,一旦我有大约300 000插入查询在InnoDB表2组的索引,并花了30分钟左右,当我每10个000插入封闭成BEGIN TRANSACTIONCOMMIT花了不到2分钟).

我建议使用:

BEGIN TRANSACTION;
SELECT ... FROM products;
UPDATE ...;
INSERT INTO ...;
INSERT INTO ...;
INSERT INTO ...;
COMMIT;
Run Code Online (Sandbox Code Playgroud)

这将导致InnoDB刷新索引一次不是几百次.

让我知道它是否有效

  • 我在游标中遇到一个问题,这个问题已经解决了(从90秒到0.9!)慢慢地我正在学习InnoDB需要什么 (2认同)

Min*_*dge 6

我有一个类似的问题,似乎InnoDB默认启用innodb_flush_log_at_trx_commit,它刷新你的硬盘日志文件上的每个插入/更新查询.硬盘的写入速度是此过程的瓶颈.

所以尝试修改你的mysql配置文件

  `innodb_flush_log_at_trx_commit  = 0`
Run Code Online (Sandbox Code Playgroud)

重启mysql服务.

我在插件上体验了x100加速.

  • 请注意,应用此选项会丢失事务安全性……如果在告诉客户端完成后断电,但在实际写入磁盘之前断电将意味着它永远丢失。 (2认同)