我的Ubuntu服务器上有一个PHP DAEMON,它在InnoDB中插入大量数据。使用该平台的人也在使用相同的表格。
DAEMON未在TRANSACTION模式下运行时,对于100,000个插入使用大约60-70秒。在TRANSACTION模式下运行时,BEGIN .... COMMIT它使用15-20秒。
然而,TRANSACTION模式会锁定表格,并阻止使用该平台的用户在执行DAEMON TRANSACTION时执行插入操作吗? 当然,锁定用户操作超过20秒的表是不可取的:)
我正在以500和500的批量插入一个FOR循环INSERT INTO(col1,col2)VALUES(a,b)等。这很好,并且运行顺畅,但是我是如果我在循环之前发出BEGIN,并且在循环之后发出COMMIT,则能够显着加快进程,但这意味着BEGIN / COMMIT之间的时间超过60秒。但是当系统进行数十万次插入时,使用该平台的人可以对同一个表进行插入。系统是否会为用户插入生成Inserts帐户,或者用户是否必须等待XX秒才能处理插入?
答案 0 :(得分:0)
根据您的描述,您使用启用了默认autocommit模式的innodb,并在循环中逐个插入记录。自动提交模式意味着每个插入都封装在自己的事务中,这很好但很慢,因为每个记录都单独保存到磁盘中。
如果您将循环插入begin
- commit
语句中的记录,则所有插入都在单个事务中运行,并且仅在commit
时持久保存到磁盘一次发布 - 这就是你体验速度增益的原因。
无论您插入记录的方式如何,innodb都会使用锁定。但是,innodb only locks the record being inserted:
INSERT在插入的行上设置独占锁。这个锁是一个 索引记录锁,而不是下一键锁(即没有间隙锁) 并且不会阻止其他会话之前插入间隙 插入的行。
在插入行之前,有一种称为插入的间隙锁 意图间隙锁定设置。此锁定表示插入的意图 这样一种方式,多个事务插入到同一个索引中 如果它们没有插入相同的间隙,则不必等待彼此 在差距内的位置。假设有索引记录 值4和7.尝试插入值的单独事务 分别为5和6,以插入意图锁定4和7之间的间隙 在获取插入行上的独占锁之前锁定,但是 不要互相阻塞,因为这些行是非冲突的。
这意味着,如果事务打开的时间较长,只插入记录,则不会干扰将记录插入同一个表的其他用户。
请注意,在循环中发出单个insert语句是将大量数据插入MySQL的效率最低的方法。
使用bulk insert(在循环中构建单个insert语句并在循环后执行它,注意max_allowed_packet设置:
使用VALUES语法的INSERT语句可以插入多行。至 执行此操作,包括多个列值列表,每个列值都包含在其中 括号并用逗号分隔。示例:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
或使用load data infile声明。
这两个解决方案可以显着加快数据插入速度,也不会导致表锁定。
答案 1 :(得分:0)
计划A:LOAD DATA
。缺点:这需要将数据写入文件。如果它已经在文件中,那么这是最好的方法。
计划B:“已批量INSERTs
” - 构建INSERT INTO t (a,b) VALUES (1,2), (3,4), ...
并执行它们。分批进行100-1000。对于大量的1行BEGIN
,这比COMMIT
.. INSERTs
更快。有autocommit=ON
。锁定/阻止将是最小的,因为每个“交易”将只有100-1000行的价值。
让我们看看SHOW CREATE TABLE
。 INDEXes
,尤其是UNIQUE
索引会对性能产生影响。我们可以进一步建议。
如果这是一个“数据仓库”应用程序,那么我们应该讨论“摘要表”。这些会大大减轻“读者”的负担,减少Fact表上索引的需要,防止锁定/阻塞,因为他们会读取不同的表。
此外,UUID的表现非常糟糕。
桌子有多大?你有多少RAM? innodb_buffer_pool_size
的价值是什么?