目次
バッチを使用挿入すると、効率が大幅に向上し、1000 アイテムごとにコミットされます。データ量が多すぎると、バッチ挿入の効率も低下します。" >データ スクリプトの作成バッチを使用挿入すると、効率が大幅に向上し、1000 アイテムごとにコミットされます。データ量が多すぎると、バッチ挿入の効率も低下します。
テスト開始 " >テスト開始
普通分页查询" >普通分页查询
相同偏移量,不同数据量" >相同偏移量,不同数据量
相同数据量,不同偏移量" >相同数据量,不同偏移量
如何优化 " >如何优化
优化偏移量大问题" >优化偏移量大问题
采用子查询方式" >采用子查询方式
采用 id 限定方式" >采用 id 限定方式
优化数据量大问题" >优化数据量大问题
ホームページ Java &#&面接の質問 インタビュアー: 1,000 万件のデータをどのようにクエリしたのですか?

インタビュアー: 1,000 万件のデータをどのようにクエリしたのですか?

Aug 15, 2023 pm 04:34 PM
java ジャワのインタビュー

最近、私は模擬面接や履歴書の最適化を全員に対して行っていますが、多くの人が 何千万ものデータを見ていることがわかりました。など 面接の質問はあなたを弱くします。
おそらく、数千万のデータを含むテーブルに遭遇したことがなく、数千万のデータをクエリすると何が起こるかわからない人もいるでしょう。

今日は実践的な操作を説明します。今回は、テスト用に

MySQL 5.7.26

をベースにしています。

準備データ 1,000 万のデータがない場合はどうすればよいですか?

データがないと作れませんか?

データ作成は難しいですか?

コードは 1,000 万を作成しますか?

それは不可能です、遅すぎるし、丸一日かかるかもしれません。データベース スクリプトを使用すると、より高速に実行できます。

テーブルの作成
CREATE TABLE `user_operation_log`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `ip` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `op_data` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr3` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr4` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr6` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr7` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr8` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr9` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr10` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr11` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `attr12` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
ログイン後にコピー
データ スクリプトの作成バッチを使用挿入すると、効率が大幅に向上し、1000 アイテムごとにコミットされます。データ量が多すぎると、バッチ挿入の効率も低下します。
DELIMITER ;;
CREATE PROCEDURE batch_insert_log()
BEGIN
  DECLARE i INT DEFAULT 1;
  DECLARE userId INT DEFAULT 10000000;
 set @execSql = 'INSERT INTO `test`.`user_operation_log`(`user_id`, `ip`, `op_data`, `attr1`, `attr2`, `attr3`, `attr4`, `attr5`, `attr6`, `attr7`, `attr8`, `attr9`, `attr10`, `attr11`, `attr12`) VALUES';
 set @execData = '';
  WHILE i<=10000000 DO
   set @attr = "&#39;测试很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的属性&#39;";
  set @execData = concat(@execData, "(", userId + i, ", &#39;10.0.69.175&#39;, &#39;用户登录操作&#39;", ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ")");
  if i % 1000 = 0
  then
     set @stmtSql = concat(@execSql, @execData,";");
    prepare stmt from @stmtSql;
    execute stmt;
    DEALLOCATE prepare stmt;
    commit;
    set @execData = "";
   else
     set @execData = concat(@execData, ",");
   end if;
  SET i=i+1;
  END WHILE;

END;;
DELIMITER ;
ログイン後にコピー

テスト開始

私のコンピューター構成は比較的低いです: win10 標準圧力 i5、読み取りおよび書き込み約 500MB SSD

Due低構成に設定した場合、このテストの準備のみを行いましたが、3148,000 個のデータが取得され、5G のディスク (インデックスなし) を占有し、38 分間実行されました。適切なコンピューター構成を備えた学生は、テスト用に複数のポイントのデータを挿入できます
SELECT count(1) FROM `user_operation_log`
ログイン後にコピー

返される結果: 3148000

3 つのクエリ時間は次のとおりです:

  • 14060 ms
  • 13755 ms
  • 13447 ms

普通分页查询

MySQL 支持 LIMIT 语句来选取指定的条数数据, Oracle 可以使用 ROWNUM 来选取。

MySQL分页查询语法如下:

SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
ログイン後にコピー
  • 第一个参数指定第一个返回记录行的偏移量
  • 第二个参数指定返回记录行的最大数目

下面我们开始测试查询结果:

SELECT * FROM `user_operation_log` LIMIT 10000, 10
ログイン後にコピー

查询3次时间分别为:

  • 59 ms
  • 49 ms
  • 50 ms

这样看起来速度还行,不过是本地数据库,速度自然快点。

换个角度来测试

相同偏移量,不同数据量

SELECT * FROM `user_operation_log` LIMIT 10000, 10
SELECT * FROM `user_operation_log` LIMIT 10000, 100
SELECT * FROM `user_operation_log` LIMIT 10000, 1000
SELECT * FROM `user_operation_log` LIMIT 10000, 10000
SELECT * FROM `user_operation_log` LIMIT 10000, 100000
SELECT * FROM `user_operation_log` LIMIT 10000, 1000000
ログイン後にコピー

查询时间如下:

##1000 アイテム61ms74ms60ms #10000 アイテム100000 記事##1000000 記事16219ms16889ms17081ms

从上面结果可以得出结束:数据量越大,花费时间越长

相同数据量,不同偏移量

SELECT * FROM `user_operation_log` LIMIT 100, 100
SELECT * FROM `user_operation_log` LIMIT 1000, 100
SELECT * FROM `user_operation_log` LIMIT 10000, 100
SELECT * FROM `user_operation_log` LIMIT 100000, 100
SELECT * FROM `user_operation_log` LIMIT 1000000, 100
ログイン後にコピー
数量初回2回目3回目
10 アイテム53ms52ms47ms
100 アイテム50ms60ms55ms
164ms180ms217ms
1609ms1741ms1764ms
偏移量第一次第二次第三次
10036ms40ms36ms
100031ms38ms32ms
1000053ms48ms51ms
100000622ms576ms627ms
10000004891ms5076ms4856ms

从上面结果可以得出结束:偏移量越大,花费时间越长

SELECT * FROM `user_operation_log` LIMIT 100, 100
SELECT id, attr FROM `user_operation_log` LIMIT 100, 100
ログイン後にコピー

如何优化

既然我们经过上面一番的折腾,也得出了结论,针对上面两个问题:偏移大、数据量大,我们分别着手优化

优化偏移量大问题

采用子查询方式

我们可以先定位偏移位置的 id,然后再查询数据

SELECT * FROM `user_operation_log` LIMIT 1000000, 10

SELECT id FROM `user_operation_log` LIMIT 1000000, 1

SELECT * FROM `user_operation_log` WHERE id >= (SELECT id FROM `user_operation_log` LIMIT 1000000, 1) LIMIT 10
ログイン後にコピー

查询结果如下:

sql花费时间
第一条4818ms
第二条(无索引情况下)4329ms
第二条(有索引情况下)199ms
第三条(无索引情况下)4319ms
第三条(有索引情况下)201ms

从上面结果得出结论:

  • 第一条花费的时间最大,第三条比第一条稍微好点
  • 子查询使用索引速度更快

缺点:只适用于id递增的情况

id非递增的情况可以使用以下写法,但这种缺点是分页查询只能放在子查询里面

注意:某些 mysql 版本不支持在 in 子句中使用 limit,所以采用了多个嵌套select

SELECT * FROM `user_operation_log` WHERE id IN (SELECT t.id FROM (SELECT id FROM `user_operation_log` LIMIT 1000000, 10) AS t)
ログイン後にコピー
采用 id 限定方式

这种方法要求更高些,id必须是连续递增,而且还得计算id的范围,然后使用 between,sql如下

SELECT * FROM `user_operation_log` WHERE id between 1000000 AND 1000100 LIMIT 100

SELECT * FROM `user_operation_log` WHERE id >= 1000000 LIMIT 100
ログイン後にコピー

查询结果如下:

sql花费时间
第一条22ms
第二条21ms

从结果可以看出这种方式非常快

注意:这里的 LIMIT 是限制了条数,没有采用偏移量

优化数据量大问题

返回结果的数据量也会直接影响速度

SELECT * FROM `user_operation_log` LIMIT 1, 1000000

SELECT id FROM `user_operation_log` LIMIT 1, 1000000

SELECT id, user_id, ip, op_data, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9, attr10, attr11, attr12 FROM `user_operation_log` LIMIT 1, 1000000
ログイン後にコピー

查询结果如下:

sql 花费时间
第一条 15676ms
第二条 7298ms
第三条 15960ms

この結果から、不要な列を減らすことでクエリ効率も大幅に向上することがわかります。

1 回目と 3 回目のクエリ速度はほぼ同じです。 「間違いなく文句を言います。なぜそんなに多くのフィールドを書きますか? * だけで完了です。

私の MySQL サーバーとクライアントは同じマシン上にあるので、クエリ データは似ていることに注意してください。資格のある学生はそれをテストできます。」 . MySQL とは別にクライアントをテストする

#SELECT * おいしいでしょう?

ところで、SELECT * が禁止される理由を付け加えたいと思います。シンプルで無頓着だからこそ美味しいんじゃないでしょうか?

2 つの主要なポイント:

  1. SELECT * 」を使用すると、データベースはより多くのオブジェクト、フィールド、権限、属性、​​およびその他の関連コンテンツを解析する必要があります。 . SQL ステートメントが複雑でハード解析が多い場合、データベースに大きな負荷がかかります。
  2. #ネットワーク オーバーヘッドが増加します。
    # ログや IconMD5 などの役に立たない大きなテキスト フィールドが誤って追加される場合があり、データ転送サイズが幾何級数的に増加します。特に、MySQL とアプリケーションは同じマシン上にないため、このオーバーヘッドは非常に明白です。

#

以上がインタビュアー: 1,000 万件のデータをどのようにクエリしたのですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

PHP対Python:違いを理解します PHP対Python:違いを理解します Apr 11, 2025 am 12:15 AM

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

See all articles