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

推薦する

HTMLのフォントがline-heightを指定しても垂直方向に中央揃えできない問題の解決方法を詳しく説明します

による写真に示されている効果を例に挙げてみましょう。明らかに、「次へ」というテキストを水平方向だけで...

Ubuntu 18.04 (物理マシン) で OpenWRT 開発環境を構成する方法

1. 仮想マシン(物理マシン)をインストールする仮想マシンまたは物理マシンにインストールできます。 ...

MySQL はリレーショナルデータベースですか?

MySQL はリレーショナル データベース管理システムです。リレーショナル データベースは、すべて...

適応幅(パーセンテージ)に応じて Div の高さを調整する純粋な CSS

今日のレスポンシブ レイアウトの要件では、サイズを自動的に調整できる多くの要素で高さと幅の適応を実現...

MySqlを最適化するためにnot inを使用する方法

最近、プロジェクトで選択クエリを使用する際に、未使用の主キー ID を除外するために not in ...

OpenSSL を使用した Kubernetes 証明書の生成の概要

Kubernetes は、基本認証、トークン認証、CA 認証の 3 種類の認証をサポートしています。...

JavaScript の基礎: スコープ

目次範囲グローバルスコープ関数のスコープもし、スイッチ、のために、その間ブロックスコープスコープチェ...

VUEユニアプリ開発環境についての簡単な説明

目次1. HBuilderXビジュアルインターフェースを通じて2. vue-cliコマンドで実行する...

複数の値を返す MySQL ストアド プロシージャ メソッドの例

この記事では、例を使用して、MySQL ストアド プロシージャで複数の値を返す方法について説明します...

CSSの固定位置属性の詳細な説明

モバイル アプリを開発する場合、Web サイトが特定の高さまでスクロールしたときにコンテンツの一部を...

Linux環境にDocker環境をインストールする(落とし穴なし)

目次インストールの前提条件ステップ1: システムの残りを確認してクリアし、Dockerの依存関係をイ...

MySQL ユーザーと権限、およびルートパスワードをクラックする方法の例

MySQL ユーザーと権限MySQL には、MySQL と呼ばれるシステムに付属するデータベースがあ...

uniapp エントリーレベル nvue クライミングピット記録の分析

目次序文こんにちは世界画像 境界線の半径を設定する実ピクセルを設定する外部CSSをインポートttfフ...

MySQL デッドロックのトラブルシューティングの全プロセス記録

【著者】 Liu Bo: Ctrip テクニカル サポート センターのシニア データベース マネージ...

Linuxはnode.jsを完全に削除し、yumコマンドで再インストールします。

最初のステップ組み込みのパッケージ管理機能で一度削除する yum 削除 nodejs npm -y ...