データベースの一括更新/ CSVファイルからの挿入


8

あるデータベースから別のデータベースへのアプリケーション固有のデータインポート機能を実装しています。

たとえば、10000行を含むCSVファイルがあります。これらの行は、データベースに挿入/更新する必要があります。

いくつかの行がデータベースに存在する場合があり、それらは更新する必要があることを意味します。データベースに存在しない場合は、それらを挿入する必要があります。

可能な解決策の1つは、1行ずつ読み取り、データベースのエントリを確認し、それに応じて挿入/更新クエリを作成することです。ただし、このプロセスでは、更新/挿入クエリを作成してデータベースで実行するのに時間がかかることがあります。CSVファイルに数百万のレコードが含まれる場合があります。

この機能を実現する他のより速い方法はありますか?

java  oracle 

分割して処理しようとすると、1回のショットで大量のCSVを読み取るとOutOfMemory

@TheNewIdiotこれは、少なくとも2 GBのRAMをJVMに送信する適切なサーバーのような十分なメモリを使用している場合は発生しません。また、CSVファイルのデータの種類や、プロセスが単一のプロセスで実行されるか、サーバーで処理される他のプロセスで実行されるかによっても異なります。

@Luiggi Mendoza:同意します。本番環境で大きなCSVファイルを処理するのに十分なメモリがあります。

回答:


7

Oracleには、External Tablesと呼ばれる優れたテクノロジーがあります。あなたのシナリオでは、データベース内から外部表を使用して、外部のプレーンテキストデータにアクセスすることができ、あなたが愛し、に使用されているSQL文をデータベース内の既存のデータを更新-たとえば、INSERTMERGEなど

ほとんどの場合、ETLを実行するには、Oracle提供のユーティリティを使用するのが最適です。そして、あなたの質問は管理上の質問のように聞こえるため、DBA Stack Exchangeに関する以前の投稿「CSVからOracleデータベースを更新する」を参照することをお勧めします。

更新:このアプローチは、データベース内の外部データの読み取りに非常に適しています。一般に、新しい形式のプレーンテキストファイルを処理する必要があるたびに、外部データ形式を定義します。外部テーブルが作成されると、実際のデータベーステーブルと同じようにクエリできます。インポートする新しいデータがあるときはいつでも、外部テーブルを再作成する必要なく、その場で基礎となるファイルを置き換えるだけです。外部テーブルは他のデータベーステーブルと同じようにクエリできるため、SQLステートメントを記述して他のデータベーステーブルにデータを入力できます。

外部テクノロジを使用すると、通常、手動で実装する他の手法と比べてオーバーヘッドが低くなります。これは、このテクノロジがOracleデータベースアーキテクチャを考慮したパフォーマンスを考慮して設計されているためです。


これが私の目標を達成するための解決策の1つであることに同意します。このアプローチを動的CSV処理にどのように適合させることができますか?つまり、私のアプリケーションユーザーは、異なる形式の複数のファイルをアップロードする機会があります(この場合、外部のストーリーをその場で作成する必要があります)。また、1つのCSVファイルには、複数のテーブルに入力する必要があるデータが含まれている場合があります。

1

SQL * Loaderを使用してCSVファイルを一時テーブルにロードしてから、MERGEステートメントを使用してデータを作業テーブルに挿入する必要があると思います。
SQL * Loaderは、外部テーブルよりも柔軟性が高く、ダイレクトパスロードを使用する場合は非常に高速です。そしてMERGEはあなたが必要とするものを正確に行います-新しいレコードを挿入し、既存のレコードを更新します。
開始するいくつかのリンク:
http : //docs.oracle.com/cd/B19306_01/server.102/b14215/ldr_concepts.htm
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016 .htm


1
SQL ローダーを使用してデータベースにデータをロードすると、DBWRプロセスまたはSQLローダープロセスがデータファイルにバッファーを書き込みます。その後、ロードされたデータを他のテーブルに移動すると、データベースは別のI / Oを実行します。この余分な作業は正当化できないと思います。ちなみに、外部テーブルがORACLE_LOADERドライバーを利用する場合、入力データ形式を定義するための構文はsqlldrユーティリティで使用されるものと同じです。これは、それらが本質的に同じテクノロジーであり、互換的に使用できるためです。最初にデータベースにデータをロードする必要がないため、このシナリオでは外部テーブルが推奨されます
Yasir Arsanukaev 2013

いつものように「それは依存する」です:)。私たちの場合、通常は最初に一時テーブルにロードし、後で処理する方が便利です。ダイレクト・パス・ロードではREDOが生成されないため、追加のI / Oは他の操作ではほとんど気付かれません。もちろん、他のケースでは他の方法がより良いでしょう。
Mindaugas Riauba 2013

0

PreparedStatementsは挿入または更新クエリの作成を非常に高速にします。3つ必要PreparedStatementsです。1つは挿入用、もう1つは更新用、もう1つは行がすでにテーブルにあるかどうかを確認するためのものです。CSVファイルと新しいデータベースの間でIDを同じに保つことができる場合は、primaryIDフィールドを使用して行が存在するかどうかを確認することも非常に高速です。

バッチ挿入を使用すると、パフォーマンスが向上する場合があります。CSVファイルを使用してストリーミングするときに、行が既に存在するかどうかを確認してから、更新を行うか、行をバッチ挿入コマンドに追加します。この2つのアプローチの速度を比較するには、このSOの質問を確認する必要があります。

このデータベースのインポートが定期的に実行する必要があるものであり、上記で概説した方法を使用してパフォーマンスに問題がある場合は、複数のワーカースレッドでタスクを処理してみることができます。このコードを実行しているマシンのプロセッサと同じ数のスレッドを使用します。

  int nThreads = Runtime.getRuntime().availableProcessors();

各スレッドは独自のDB接続を取得し、コードがファイルを反復処理するときに、CSVの行をさまざまなスレッドに渡すことができます。これははるかに複雑なので、パフォーマンス要件によって強制された場合にのみこれを実行します。


お返事をありがとうございます。繰り返しになりますが、これには、CSVファイルの解析と値の準備済みステートメントへの入力が必要です。「外部テーブル」アプローチを使用すると、ファイルの解析をデータベース側に移動できるため、アプリケーションで処理する必要がありません。また、アプリケーションでHibernateとJPAを使用しています。私は、ファイル解析を行わない、優れたパフォーマンス、保守可能で柔軟なJPA / Hibernate / Oracleの組み合わせであるオプションを探しています。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.