MySql クイック挿入数千万の大規模データの例

MySql クイック挿入数千万の大規模データの例

データ分析の分野では、データベースは私たちの強力な助けとなります。クエリ時間を受け入れるだけでなく、それに基づいてさらに分析を行うこともできます。したがって、データベースにデータを挿入する必要があります。実際のアプリケーションでは、数千万、あるいはそれ以上の量のデータが頻繁に発生します。素早く挿入する方法がなければ、効果がなく、多くの時間がかかります。

アリババの天地ビッグデータアルゴリズムコンテスト(人気音楽のトレンド予測)に参加したとき、このような問題に遭遇しました。データベースクエリと挿入を最適化する前は、多くの時間を無駄にしていました。最適化前は、1500万のデータ項目を挿入するだけで(最も基本的な1つずつの挿入を使用)、信じられないほどの12時間もかかっていました。これにより、データベースの挿入とクエリ操作を最適化して効率を向上させる方法についても考えるようになりました。

継続的な最適化の過程で、パフォーマンスが大幅に向上しました。データベースから26,000曲以上のダウンロード数、再生数、お気に入り数を時系列で照会・集計する処理において、クエリ生成操作速度が推定40時間から1時間強に短縮されました。データベース挿入に関しては、パフォーマンスが大幅に向上しました。新しいデータセットでテストしたところ、20 分間で 5,490 万件を超えるデータが挿入されました。以下に私の考えを述べさせてください。

最適化プロセスは 2 つのステップに分かれています。最初のステップは、実験的な静的リーダーを使用して CSV ファイルからデータを読み取ることです。データが一定量に達すると、データベース プログラムへのマルチスレッド挿入が開始されます。2 番目のステップは、MySQL バッチ挿入操作を使用することです。

最初のステップは、ファイルを読み取り、マルチスレッドの挿入を開始することです

ここで、ある量に到達するかどうかは考慮すべき問題です。私の実験では、この量として 100W を使い始めましたが、新たな問題が発生し、Java ヒープ メモリがオーバーフローしたため、最終的に 10W が標準として使用されました。

もちろん、お好みに応じて他の量でも構いません。

java.io.BufferedReader をインポートします。
java.io.FileNotFoundException をインポートします。
java.io.FileReader をインポートします。
java.io.IOException をインポートします。
java.util.ArrayList をインポートします。
java.util.List をインポートします。
 
preprocess.ImportDataBase をインポートします。
 
パブリッククラスMuiltThreadImportDB {
 
 /**
  * 大容量ファイルとストレージの Java マルチスレッド読み取り * 
  * @param 引数
  */
 プライベート静的int m_record = 99999;
 プライベート静的 BufferedReader br = null;
 プライベートArrayList<String>リスト;
 プライベート静的int m_thread = 0;
 静的{
 試す {
  br = 新しいバッファリーダー(
  新しいファイルリーダー(
  "E:/tianci/IJCAI15 Data/data_format1/user_log_format1.csv"),8192);
 
 } キャッチ (FileNotFoundException e) {
  e.printStackTrace();
 }
 試す {
  br.readLine(); // CSV ヘッダーを削除
 } キャッチ (IOException e) {
  e.printStackTrace();
 }
 }
 
 パブリックボイド開始() {
 文字列;
 整数カウント = 0;
 リスト = 新しいArrayList<String>(m_record + 1);
 同期 (br) {
  試す {
 ((line = br.readLine()) != null) の場合 {
  カウント < m_record) {
 リストに行を追加します。
 カウント++;
  } それ以外 {
 リストに行を追加します。
 カウント = 0;
 スレッド t1 = new Thread(new MultiThread(list),Integer.toString(m_thread++));
 t1.開始();
 リスト = 新しいArrayList<String>(m_record + 1);
  }
 }
 
 if (リスト != null) {
  スレッド t1 = new Thread(new MultiThread(list),Integer.toString(m_thread++));
  t1.開始();
 }
  } キャッチ (IOException e) {
 e.printStackTrace();
  }
 }
 }
 
 パブリック静的voidメイン(String[] args) {
 新しい MuiltThreadImportDB().start();
 } 
}

2番目のステップは、マルチスレッドを使用してデータをバッチで挿入することです。

クラス MultiThread は Runnable を実装します {
 プライベートArrayList<String>リスト;
 
 パブリックマルチスレッド(ArrayList<String>リスト) {
 this.list = リスト;
 }
 
 パブリックボイド実行() {
 試す {
  ImportDataBase を挿入 = 新しい ImportDataBase(リスト);
  挿入を開始します。
 } キャッチ (FileNotFoundException e) {
  e.printStackTrace();
 }
 このリストを表示します。
 }
 
 パブリック void display(List<String> リスト) {
 // for (文字列 str : リスト) {
 // System.out.println(str);
 // }
 System.out.print(Thread.currentThread().getName() + " :");
 System.out.println(リストのサイズ());
 }
 
}

バッチ操作では、MySQL の prepareStatement クラスが使用され、もちろん statement クラスのバッチ操作も使用されますが、パフォーマンスは前者ほど良くありません。前者は毎秒 10,000 以上の挿入速度に達することができますが、後者は 2,000 以上しか達しません。

パブリック int insertUserBehaviour(ArrayList<String> sqls) は SQLException をスローします {
 
 文字列 sql = "user_behaviour_log に挿入 (user_id、item_id、cat_id、merchant_id、brand_id、time_stamp、action_type)"
 + " 値(?,?,?,?,?,?,?)";
 事前ステートメント = conn.prepareStatement(sql);
 (int i = 0; i < sqls.size(); i++) の場合 {
  UserLog ログ = 新しい UserLog(sqls.get(i));
  プレStmt.setString(1, log.getUser_id());
  プレStmt.setString(2, log.getItem_id());
  プリステージ.setString(3, log.getCat_id());
  事前Stmt.setString(4, log.getMerchant_id());
  preStmt.setString(5, log.getBrand_id());
  タイムスタンプを6に設定します。
  アクションタイプをログに記録します。
  preStmt.addBatch();
  ((i + 1) % 10000 == 0) の場合 {
 preStmt.executeBatch();
 conn.commit();
 preStmt.clearBatch();
  }
 }
 preStmt.executeBatch();
 conn.commit();
 1 を返します。
 }

もちろん、さまざまな MySQL ストレージ エンジンである InnoDB と MyISM でも実験しました。実験結果では、InnoDB の方が高速 (約 3 倍) であることが示されましたが、これは MySQL の新しいバージョンに関係している可能性があります。著者の MySQL バージョンは 5.6 です。

最後に、大量データでの挿入速度を向上させる方法をまとめます。

Java コードの場合は、マルチスレッド挿入とバッチ送信を使用します。

データベースに関しては、テーブル構造を確立するときにインデックスを使用しないでください。そうしないと、挿入プロセス中にインデックス B+ ツリーを維持する必要があります。ストレージ エンジンを変更します。通常、デフォルトは InnoDB です (新しいバージョンではデフォルトを使用できますが、古いバージョンでは必要な場合があります)。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • インデックスを使用して数千万のデータを持つ MySQL のクエリ速度を最適化する
  • MySQLループは数千万のデータを挿入する
  • 数千万のMySQLデータ量を素早くページ分割する方法
  • MySQL で大量のデータ (数千万) を素早く削除するためのいくつかの実用的なソリューションの詳細な説明
  • MySQL 数千万のビッグデータに対するSQLクエリ最適化の知識ポイントのまとめ
  • MySQLで数千万のテストデータを素早く作成する方法
  • MySQL数千万の大規模データに対する30のSQLクエリ最適化テクニックの詳細な説明
  • 数千万のデータを扱うMySQLのページングクエリのパフォーマンスを最適化する
  • 数千万ページ分のMySQL高速ページングを最適化する方法
  • MySQLデータベースの数千万件のデータクエリとストレージの詳細な説明

<<:  Reactでプロキシを有効にする2つの実用的な方法

>>:  Ubuntu 18.04 Linux システムに JDK と Mysql をインストールする方法

推薦する

Nginx ドメイン名の書き換えとワイルドカードドメイン名の解決を設定する方法

この記事では、ドメイン名の書き換えとワイルドカードドメイン名の解決を行うための Nginx の設定方...

MySQL マスタースレーブレプリケーションでエラーをスキップする方法

1. 従来のbinlogマスタースレーブレプリケーション、エラー報告をスキップする方法 mysql&...

du コマンドを使用して Linux システム ディレクトリのサイズを取得する方法

Linux システムを使用したことがある人なら、Linux システムの ls コマンドは通常、ファイ...

Linux システムで tcpdump を使用してパケットをキャプチャする方法

まずサンプルコードを見てみましょう: 1. 共通パラメータ tcpdump -i eth0 -nn ...

HTML タグ: サブタグと sup タグ

今日はあまり使わないHTMLタグ「subタグ」と「supタグ」を紹介します。関連記事: HTML タ...

MySQL学習データベース操作DML初心者向け詳細解説

目次1. ステートメントを挿入する1.1 行を挿入する1.2 複数行を挿入する1.3 クエリステート...

Mysql 5.7.19 無料インストール バージョンで遭遇した落とし穴 (コレクション)

1. 公式ウェブサイトから 64 ビットの zip ファイルをダウンロードします。 2. インスト...

JavaScript で配列の最大値と最小値を実装する 6 つの方法

配列[1,8,5,4,3,9,2]が与えられた場合、配列の最大値9と最小値1を取得するアルゴリズムを...

この記事では、CSSのようなJSモジュールをインポートする方法を説明します。

目次序文構築可能なスタイルシートとは何ですか? CSSモジュールスクリプトの使用インポートアサーショ...

Reactはルーティングを使用してログインインターフェースにリダイレクトします

前回の記事では、webpack と react 環境を設定した後、ログイン インターフェースとその後...

MySQL の NULL と空の文字列

最近、MySQL に触れました。昨日、テーブル構造情報を格納するための新しいテーブルを作成しました。...

Nginx+SpringBoot による負荷分散の実装例

負荷分散の概要Nginx の負荷分散実装を紹介する前に、負荷分散の分類について簡単に説明します。負荷...

nginx が動的と静的の分離を実装する方法の例

目次server1にnginxをデプロイするサーバーにlnmpを展開するノード3にhttpdをデプロ...

HTML ウェブページハイパーリンクタグ

HTML ウェブ ページのハイパーリンク タグの学習チュートリアル リンク タグの属性 リンクは、ウ...

CSS変数を使用して、クールで素晴らしいフローティング効果を実現します。

最近、Grover の Web サイトで楽しいホバー アニメーションを見つけ、自分自身のインスピレー...