【发布时间】:2016-06-17 10:47:50
【问题描述】:
我们正在使用 Python 和 LOAD DATA INFILE 将数据从 CSV 加载到我们的暂存数据库中。从登台开始,我们有 sql 脚本将数据移动到我们的实际生产数据库中。
与从暂存中选择行并将它们插入生产相比,LOAD DATA INFILE 速度快如闪电。
我们在 5.7 上,使用 InnoDB,我们应用了以下配置来优化我们的插入:
- 将 innodb_autoinc_lock_mode 设置为 2
- 将 innodb 缓冲池大小设置为内存的一半 (16GB)
- 将日志缓冲区大小设置为 4GB
- 我们正在使用 TRANSACTIONS
- 使用 SET autocommit=0;
与 LOAD DATA INFILE 相比,从一个表到另一个表的插入仍然明显慢。
当我查看 IO 写入时,加载数据 infile 时最高可达 30 MB/s,而正常插入时最高为 500KB/秒。
我们有什么方法可以提高这种性能,还是我们需要完全重新考虑我们的方法。我可以考虑使用 OUTFILE 进行子查询并使用 INFILE 将其加载回来,但这听起来不是正确的方法。
还有声明:
INSERT INTO documentkey (documentClassCode,dId,fileTypeCode,internet,pathId,creationTime,signature,CSVimportId)
SELECT case when csv.`Document Class` is null
then (select classCode from mydb.class where classDesc = 'Empty'
And LookupId = (select LookupId from mydb.Lookup where LookupGroupCode = 'C' and EntityLookedup = 'documentkey')
)
else (select classCode from mydb.class where classDesc = csv.`Document Class`
And LookupId = (select LookupId from mydb.Lookup where LookupGroupCode = 'C' and EntityLookedup = 'documentkey')
)
end,
csv.`dId`,
(select typeCode from mydb.type
Where typeDesc = csv.`File Type`
And LookupId = (select LookupId from mydb.Lookup where LookupGroupCode = 'T' and EntityLookedup = 'documentkey')
),
case when csv.`message ID` is null
then (select messageIncrId from message where internetdesc = 'Empty')
else case when exists (select internetMessageIncrId from internetMessage where internetdesc = csv.`Internet Message ID`)
then (select internetMessageIncrId from internetMessage where internetdesc = csv.`Internet Message ID`)
else 0
end
end,
case when exists (select pathId from Path where pathDesc = csv.`path`)
then (select pathId from Path where pathDesc = csv.`path`)
else 0
end,
case when csv.`Creation Time` <> '' then STR_TO_DATE(csv.`Creation Time`, '%d/%m/%Y %H:%i:%s') else '2016-06-16 10:00:00' end,
#STR_TO_DATE(csv.`Creation Time`, '%Y-%m-%d %H:%i:%s'),
csv.`Signature Hash`,
1
#csv.`CSV import id`
FROM `mydb_stage`.`csvDocumentKey` csv
where csv.`dId` is not null and csv.threadId = @thread;
选择查询的一部分只需要几分之一秒。
解释:
'1', 'PRIMARY', 'csv', NULL, 'ALL', NULL, NULL, NULL, NULL, '1', '100.00', 'Using where'
'12', 'DEPENDENT SUBQUERY', 'path', NULL, 'eq_ref', 'pathDesc_UNIQUE', 'pathDesc_UNIQUE', '1026', 'func', '1', '100.00', 'Using where; Using index'
'11', 'DEPENDENT SUBQUERY', 'path', NULL, 'eq_ref', 'pathDesc_UNIQUE', 'pathDesc_UNIQUE', '1026', 'func', '1', '100.00', 'Using where; Using index'
'10', 'SUBQUERY', 'message', NULL, 'const', 'messageDesc_UNIQUE', 'messageDesc_UNIQUE', '2050', 'const', '1', '100.00', 'Using index'
'9', 'DEPENDENT SUBQUERY', 'message', NULL, 'eq_ref', 'messageDesc_UNIQUE', 'messageDesc_UNIQUE', '2050', 'func', '1', '100.00', 'Using where; Using index'
'8', 'DEPENDENT SUBQUERY', 'message', NULL, 'eq_ref', 'messageDesc_UNIQUE', 'messageDesc_UNIQUE', '2050', 'func', '1', '100.00', 'Using where; Using index'
'6', 'DEPENDENT SUBQUERY', 'type', NULL, 'eq_ref', 'typeDesc_UNIQUE', 'typeDesc_UNIQUE', '1026', 'func', '1', '100.00', 'Using index condition; Using where'
'7', 'SUBQUERY', 'Lookup', NULL, 'ref', 'PRIMARY', 'PRIMARY', '6', 'const', '3', '10.00', 'Using where'
'4', 'SUBQUERY', 'class', NULL, 'const', 'classDesc_UNIQUE', 'classDesc_UNIQUE', '1026', 'const', '1', '100.00', NULL
'5', 'SUBQUERY', 'Lookup', NULL, 'ref', 'PRIMARY', 'PRIMARY', '6', 'const', '2', '10.00', 'Using where'
'2', 'DEPENDENT SUBQUERY', 'class', NULL, 'eq_ref', 'classDesc_UNIQUE', 'classDesc_UNIQUE', '1026', 'func', '1', '20.00', 'Using index condition; Using where'
'3', 'SUBQUERY', 'Lookup', NULL, 'ref', 'PRIMARY', 'PRIMARY', '6', 'const', '2', '10.00', 'Using where'
【问题讨论】:
-
LOAD DATA速度快的一个原因是它实际上并没有做任何数据库工作,而INSERT是。 -
@TimBiegeleisen 我假设它使用某些对用户透明的配置设置运行,我想你可以实现类似的配置,从而实现 INSERT 的性能。这只是一个如何做的问题。
-
如何选择和插入数据。你能告诉我们查询吗
-
@BerndBuffen 我已经添加了声明
-
@L4zl0w - 谢谢,能否向我们展示 SELECT 语句的解释(不带 INSERT...):EXPLAIN SELECT case when csv.
Document Classis null then (select classCode from mydb.class where classDesc = 'Empty' ....... ; 看起来您从表中选择数据的查询非常慢
标签: mysql performance innodb