データ分析の分野では、データベースは私たちの強力な助けとなります。クエリ時間を受け入れるだけでなく、それに基づいてさらに分析を行うこともできます。したがって、データベースにデータを挿入する必要があります。実際のアプリケーションでは、数千万、あるいはそれ以上の量のデータが頻繁に発生します。素早く挿入する方法がなければ、効果がなく、多くの時間がかかります。 アリババの天地ビッグデータアルゴリズムコンテスト(人気音楽のトレンド予測)に参加したとき、このような問題に遭遇しました。データベースクエリと挿入を最適化する前は、多くの時間を無駄にしていました。最適化前は、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 を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
>>: Ubuntu 18.04 Linux システムに JDK と Mysql をインストールする方法
この記事では、ドメイン名の書き換えとワイルドカードドメイン名の解決を行うための Nginx の設定方...
1. 従来のbinlogマスタースレーブレプリケーション、エラー報告をスキップする方法 mysql&...
Linux システムを使用したことがある人なら、Linux システムの ls コマンドは通常、ファイ...
まずサンプルコードを見てみましょう: 1. 共通パラメータ tcpdump -i eth0 -nn ...
今日はあまり使わないHTMLタグ「subタグ」と「supタグ」を紹介します。関連記事: HTML タ...
目次1. ステートメントを挿入する1.1 行を挿入する1.2 複数行を挿入する1.3 クエリステート...
1. 公式ウェブサイトから 64 ビットの zip ファイルをダウンロードします。 2. インスト...
配列[1,8,5,4,3,9,2]が与えられた場合、配列の最大値9と最小値1を取得するアルゴリズムを...
目次序文構築可能なスタイルシートとは何ですか? CSSモジュールスクリプトの使用インポートアサーショ...
前回の記事では、webpack と react 環境を設定した後、ログイン インターフェースとその後...
最近、MySQL に触れました。昨日、テーブル構造情報を格納するための新しいテーブルを作成しました。...
負荷分散の概要Nginx の負荷分散実装を紹介する前に、負荷分散の分類について簡単に説明します。負荷...
目次server1にnginxをデプロイするサーバーにlnmpを展開するノード3にhttpdをデプロ...
HTML ウェブ ページのハイパーリンク タグの学習チュートリアル リンク タグの属性 リンクは、ウ...
最近、Grover の Web サイトで楽しいホバー アニメーションを見つけ、自分自身のインスピレー...