2016-06-17 3 views
0

私たちはPythonとLOAD DATA INFILEを使用して、CSVからステージングデータベースにデータをロードしています。ステージングから、実際の本番データベースにデータを移動するSQLスクリプトがあります。サブセレクション付きMySQLインサート

LOAD DATA INFILEは、ステージングから行を選択して本番環境に挿入するのに比べて高速です。

我々は、5.7であるInnoDBテーブルを使用して、我々は我々のインサートを最適化するために、以下の構成を適用した:メモリ(16ギガバイト)の半分に

  • セットinnodb_autoinc_lock_mode InnoDBのバッファプールのサイズを設定し
  • 2にします
  • ログバッファサイズを4GBに設定
  • トランザクションを使用しています
  • SETオートコミット= 0を使用してください。

まだ、あるテーブルから別のテーブルへの挿入は、LOAD DATA INFILEと比較して大幅に遅くなります。

通常の挿入では最大500KB /秒ですが、負荷データinfileの場合は30MB/sまで上がります。

このパフォーマンスを改善する方法はありますか、私たちのアプローチを完全に再考する必要がありますか?サブクエリに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」が高速である理由の1つは、実際にはデータベースの内容を実行していないという理由がありますが、「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

MySQLがACIDに準拠しており、ディスクの1つのI/Oを使用して挿入を実行するため、INSERTは遅いです。トランザクションに挿入物をグループ化すると、ディスクは1つのI/Oを使用できますが、より多くの帯域幅を使用できます。 LOAD DATA INFILEはSQLレイヤーを避け、ディスクを効率的に使用します。遅くなっている理由は、ハードドライブのためです。あなたのdbサーバーの販売された状態のドライブを取得し、そのIOPS数に注意してください。最適なコードを書くことで何も解決できません。これはハードウェアにも関連しているので、コードだけでこれまでのところできます。 –

+0

私は理解していますが、このステートメントは他のより簡単な挿入ステートメントよりもかなり遅いです。私は20倍遅く話しています。このステートメントでは、150〜400KBのディスクへの書き込みしかありません。それはIOのボトルネックではありません。 – L4zl0w

関連する問題