2016-06-17 59 views
0

我们正在使用Python和LOAD DATA INFILE将CSV数据加载到我们的临时数据库中。从分段我们有SQL脚本将数据移动到我们的实际生产数据库。MySQL插入与子选择慢

LOAD DATA INFILE与从分段中选择行并将其插入生产相比闪电般快速。

我们是5.7,使用InnoDB和我们应用以下的配置给我们的刀片优化:

  • 设置innodb_autoinc_lock_mode 2
  • 设置InnoDB缓冲池大小的内存(16GB)的一半
  • 将日志缓冲大小设置为4GB
  • 我们正在使用事务
  • 使用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' 
+0

“LOAD DATA”速度很快的一个原因是因为它实际上并没有做任何数据库的工作,而INSERT是。 –

+0

@TimBiegeleisen我认为它运行时对于用户是透明的某些配置设置,我想你可以实现类似的配置,因此可以实现INSERT的性能。这只是一个问题。 – L4zl0w

+0

如何选择并插入数据。您可以向我们展示查询 –

回答

1

你不提,为什么你要改变你的方法,特别是如果性能是你首要目标。
SELECT可以一样快卸表中的一个文件,并已在MySQL的文档
明确指出从insert-speed

当从一个文本文件,使用LOAD DATA INFILE装载表。这是 通常比使用INSERT语句快20倍。请参见第 段14.2.6“LOAD DATA INFILE语法”。

+0

感谢,我们需要在不到12小时的时间内将10亿条记录加载到分期中,并从那里进入生产。现在把唱片放入舞台不是问题,但从舞台到制作需要很长时间。我不明白的是,如果你的SELECT语句速度很快,为什么select中的INSERT很慢。我会想象,select语句的结果在内存中,从它插入的位置应该很快。但我明显错过了一些东西,因为这不是我所经历的。 – L4zl0w

+0

'INSERT'速度很慢,因为MySQL符合ACID标准,并使用1个I/O磁盘来执行插入操作。在事务中对插入进行分组可让您的磁盘使用1个I/O,但可以使用更多的带宽。 LOAD DATA INFILE避免了SQL层并高效地使用磁盘。你遇到缓慢的原因是因为你的硬盘。为您的数据库服务器获取售出的状态驱动器,并注意其IOPS计数。你不会通过编写最佳代码来解决任何问题 - 这也与硬件有关,你只能单独使用代码。 –

+0

我明白,但是这个语句比其他更简单的插入语句慢得多。我说话慢了20倍。使用此语句仅在磁盘上写入150-400KB。这不是IO瓶颈。 – L4zl0w