大量のデータ(単一タイプのエンティティ)をAmazonのDynamoDBからMySQLDBに移行します。Hibernateを使用して、このクラスをmysqlエンティティにマップしています。約300万のエンティティがあります(リストプロパティの行を除く)。クラスマッピングの概要は次のとおりです。
@Entity
@Table(name = "CUSTOMER")
public class Customer {
@Id
@Column(name = "id")
private String id;
//Other properties in which all of them are primitive types/String
@ElementCollection
@CollectionTable(name = "CUSTOMER_USER", joinColumns = @JoinColumn(name = "customer_id"))
@Column(name = "userId")
private List<String> users;
// CONSTRUCTORS, GETTERS, SETTERS, etc.
}
usersは文字列のリストです。次のような2つのmysqlテーブルを作成しました。
CREATE TABLE CUSTOMER(id VARCHAR(100), PRIMARY KEY(id));
CREATE TABLE CUSTOMER_USER(customer_id VARCHAR(100), userId VARCHAR(100), PRIMARY KEY(customer_id, userId), FOREIGN KEY (customer_id) REFERENCES CUSTOMER(id));
注: hibernateにID値を生成させることはありません。一意であることが保証されている、お客様のエンティティにIDを割り当てています。
これがhibernate.cfg.xmlです:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property>
<property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property>
<property name="hibernate.connection.url"> jdbc:mysql://localhost/xxx </property>
<property name="hibernate.connection.username"> xxx </property>
<property name="hibernate.connection.password"> xxx </property>
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<property name="hibernate.jdbc.batch_size"> 50 </property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="c3p0.min_size">30</property>
<property name="c3p0.max_size">70</property>
</session-factory>
</hibernate-configuration>
それぞれがDynamoからデータを読み取り、Hibernateを介してMySQlDBに挿入するスレッドをいくつか作成しています。各スレッドの機能は次のとおりです。
// Each single thread brings resultItems from DynamoDB
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
for(int i = 0; i < resultItems.size(); i++) {
Customer cust = new Customer(resultItems.get(i));
session.save(cust);
if(i % BATCH_SIZE == 0) {
session.flush();
session.clear();
}
}
tx.commit();
session.close();
独自のパフォーマンス監視機能があり、全体的な読み取り/書き込みパフォーマンスを継続的にログに記録しています。問題は、移行は(平均で)1500アイテム/秒の読み取り/書き込みから始まりますが、CUSTOMERテーブルとCUSTOMER_USERテーブルの行数が増える限り(数分後、r / w速度は約500アイテム/)遅くなり続けます。秒)。私はHibernateの経験がありません。ここに、私の質問があります。
注1ユーザーのリスト以外の残りのプロパティはすべてint、boolean、Stringなどであるため、すべてのプロパティを記述しませんでした。
注2すべてのポイントがテストされており、パフォーマンスに悪影響を与えることはありません。mysql dbに何も挿入しない場合、読み取り速度は何時間も安定しています。
注3mysqlテーブルの構造、構成設定、セッション/トランザクション、接続プールの数、バッチサイズなどに関する推奨事項/ガイダンスは非常に役立ちます。
これらの2つのテーブルにデータを挿入する以外に、Hibernateトランザクションで何もしていないと仮定するとStatelessSession session = sessionFactory.openStatelessSession();
、通常のセッションの代わりに使用して、キャッシュを維持するオーバーヘッドを減らすことができます。ただし、ネストされたコレクションオブジェクトを個別に保存する必要があります。https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.htmlを参照してください
だからそれは次のようなものかもしれません-
// Each single thread brings resultItems from DynamoDB
StatelessSession session = factory.openStatelessSession();
Transaction tx = session.beginTransaction();
for(int i = 0; i < resultItems.size(); i++) {
Customer cust = new Customer(resultItems.get(i));
Long id = session.save(cust); // get the generated id
// TODO: Create a list of related customer users and assign the id to all of them and then save those customer user objects in the same transaction.
if(i % BATCH_SIZE == 0) {
session.flush();
session.clear();
}
}
tx.commit();
session.close();
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加