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 をインストールする方法

推薦する

WeChat ミニプログラム ユーザー認証のベストプラクティス ガイド

序文WeChat アプレットを開発する際には、ユーザーの権限が必要なページを使用する必要があることが...

HTML メタタグの使用の概要 (推奨)

メタタグ機能METAタグは、HTMLタグのHEAD領域にある重要なタグです。文書の文字セット、使用言...

事例を通してLinux NFSの仕組みを詳細に分析

前回の記事に引き続き、web02 サーバーを作成し、web01 サーバーと web02 サーバーの ...

MySQL における主キーが 0 であることと主キーの自己選択制約の関係についての詳しい説明 (詳細)

序文この記事は主にMySQLの主キー0と主キー自己排除制約の関係を紹介し、皆さんの参考と学習のために...

HTML 挿入画像の例 (HTML 追加画像)

HTML に画像を挿入するには、画像を表示するための HTML タグが必要です。これは、img タ...

HTML フォーム コントロールの無効な属性の読み取り専用と無効の概要

HTML でフォームの送信を無効にする方法は 2 つあります。 1. コントロールタグにreadon...

mysql5.6 マスタースレーブ設定と非同期の問題の詳細な説明

目次1. MySQL マスタースレーブレプリケーションの原理2. MySQLのコンパイルとインストー...

Dockerのオンラインおよびオフラインインストールと一般的なコマンド操作

1. テスト環境名前バージョンセント7.6ドッカー18.09.06 2. オンラインインストールここ...

MySQLのバッファプールの詳細な説明

MySQL のデータはディスクに書き込む必要があることは誰もが知っています。ディスクの読み取りと書き...

Linux環境でユーザーにsudo権限を追加する方法

sudo 設定ファイルsudo のデフォルトの設定ファイルは /etc/sudoers です。一般的...

Kubernetes を使用して Springboot または Nginx をデプロイするための詳細なチュートリアル

1 はじめに「Maven がワンクリックで Springboot を Docker リポジトリにデプ...

Dapr を使用してマイクロサービスをゼロから簡素化する例

目次序文1. Dockerをインストールする2. Dapr CLIをインストールする3. Net6 ...

Vueカスタム命令の詳細な説明

目次Vueカスタムディレクティブカスタムディレクティブフック機能出力関連属性アプリケーション例要約す...

ViteでReactプロジェクトを構築する方法

目次序文Viteプロジェクトを作成する改修プロジェクトディレクトリの規則その他の構成序文毎日鳩、火ば...

MySQL 学習データベースバックアップの詳細な説明

目次1.DB、DBMS、SQL 2. データベースの特徴3. SQL分類4. MySQLを起動および...