2011-08-27 58 views
9

我有一个大的MySQL表(〜10百万行,6.5G)我用它来读取&写入。这是MyISAM,并且由于MyISAM的所有表写入锁定,我获得了很多锁定。InnoDB与MyISAM插入查询时间

我决定尝试移动到推荐读/写表的InnoDB,它只锁定写入的特定行。

转换后,我测试了插入语句,结果显示它在InnoDB表中比在MyISAM表中花费的时间多15倍(从0.1秒到1.5秒)。这是为什么?

我还没有为InnoDB配置任何东西,并计划添加分区,但这个数字对我来说仍然是意外的。当然这些表是相同的,相同的索引等

附加信息根据请求:

2索引。 primary是Big INT类型的data_id,varchar(255)类型是非唯一user_id。

插入约150行,具有相同的user_id。

索引的大小:200 MB在MyISAM中,400MB InnoDB的

+3

你能告诉我们索引吗?这是插入时间过长的最可能原因。 – wallyk

+0

我有2个索引,data_id是主键,user_id不是唯一的。我的插入约150行,具有相同的user_id(它有一个索引)。 – normalppl

+0

但每个索引的内容是什么?如果有一堆斑点,那么肯定会很难索引。但如果它们是整数或其他琐碎的类型,那么很难理解为什么性能会很差。 – wallyk

回答

5

related answer表明innodb_flush_log_at_trx_commit变量设置为2是容易提高性能时写入到读出的比率相对较高。有关更多信息,请参见the documentation

+0

我现在只做测试。所以没有读数,只有150行的一个插入,想要首先找出这一个。 – normalppl

+1

这对我造成了巨大的影响。插入7500行而不更改'innodb_flush_log_at_trx_commit'需要5分钟。将其更改为0或2将相同的INSERT减少到3秒。 – qris

3

记住InnoDB处理密钥的方式会导致麻烦。因为所有东西都按照主键的顺序存储在磁盘上,而主键的非自动增量可能会导致大部分表都在任何插入的磁盘上移动(我遇到了这个问题,当我有一个数据透视表并使用组合的ID作为主键)。在磁盘上移动数据很慢。

此外,InnoDB的索引尺寸可能更大,因为每个索引也包含主键。检查以确保您没有遇到任何内存限制。

+0

我没有想到它会更快,我意识到它应该有很多读/写的帮助。但是,如果我通常执行的基本插入需要15次以上(从0.1秒到1.5秒),听起来好像有些东西不好,不是吗? – normalppl

+1

是的,对不起,读15%不是15x - 可能有些问题 – jisaacstone

4

我认为,InnoDB实现了真正的ACID,并且做了很多fsync()s来保存数据。 MyISAM不是一个真正的ACID,并且少了fsync()。

There are recomendations to kill fsync当你需要在

If you want to load data into InnoDB quickly: 
* use as large an InnoDB buffer cache as possible 
* make the InnoDB log files as large as possible 
* minimize the number of unique indexes on your tables 
* disable all calls to fsync from InnoDB. You have to hack the code to 
get this, or look at the Google patch. Of course, you only want to run 
in this mode when loading the table. 

And lists says加载巨大的数据:

的MyISAM总是在 '非同步' 模式运行 ,也就是说,它永远不会调用的fsync()来刷新该文件以 的磁盘。

InnoDB的nosync可用于测试fsync()中某些操作系统/计算机的速度是否非常慢 。但它不应该用于生产系统。

同样的消息说,即InnoDB的有时使用其他同步方法:

然后InnoDB使用的fsync()来刷新数据和日志文件。如果指定了O_DSYNC为 ,InnoDB使用O_SYNC打开并刷新日志文件,但使用fsync()刷新数据文件。如果指定了O_DIRECT(从MySQL-4.0.14开始的某些 Linux版本上可用),InnoDB使用O_DIRECT打开 数据文件,并使用fsync()刷新数据和日志文件。请注意, InnoDB不使用fdatasync()或O_DSYNC,因为在许多Unix版本上都存在问题 。

2

首先,您的测试是无效的,因为行级锁的速度增益对表级锁,当你有并发来了!只有一个线程插入,在这两种情况下,每个插入都有一个锁定/解锁,并且插入不会等待要释放的表级锁定。

秒,如JIStone所述,当表的大小大于缓冲池时,非顺序主键是插入的性能杀手。

第三,缓冲池大小是InnoDB中最重要的设置之一。尽可能使它成为可能(建议设置为可用RAM的80%)。

接下来,如@wallyk所述,innodb_flush_log_at_trx_commit对于I/O操作的速度至关重要。

接下来,innodb_log_file_size和innodb_buffer_file_size对于重要。

接下来,请记住,由于您有两个唯一索引,因此在InnoDB可以插入行之前,必须检查索引中是否存在该值,并且索引较大。

没有关于表和索引的详细信息,我不能给你更多的建议,但请记住,没有存储引擎是万能的,虽然通常只需更改存储引擎就可以获得很多速度,在大型系统中增加索引或调整一个变量,事情比这更复杂。但是,正如我所说的,您不应该比较隔离测试中的原始插入速度,您必须尽可能使测试尽可能接近实际应用。

更新:一个更尖 在这两种MyISAM和InnoDB,多插入件(插入....值(...),(...),(...))更快。另外,在InnoDB中,您可以在事务中进行插入操作,从而在事务完成之前禁用更新非唯一索引,并且速度也更快(但不要执行大型事务,因为实际上这会由于所使用的隔离级别而降低速度;行版本化的方式)。