MySQL で制限を使用するとパフォーマンスに影響するのはなぜですか?

MySQL で制限を使用するとパフォーマンスに影響するのはなぜですか?

まず、MySQL のバージョンについて説明します。

mysql> バージョンを選択します();
+-----------+
| バージョン() |
+-----------+
| 5.7.17 |
+-----------+
セット内の 1 行 (0.00 秒)

テーブル構造:

mysql> desc テスト;
+--------+----------------------+------+-----+---------+----------------+
| フィールド | タイプ | Null | キー | デフォルト | 追加 |
+--------+----------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| val | int(10) 符号なし | NO | MUL | 0 | |
| ソース | int(10) 符号なし | NO | | 0 | |
+--------+----------------------+------+-----+---------+----------------+
セット内の 3 行 (0.00 秒)

id は自動インクリメントの主キーであり、val は一意でないインデックスです。

合計500万件の大量のデータを投入します。

mysql> テストから count(*) を選択します。
+----------+
| カウント(*) |
+----------+
|5242882|
+----------+
セット1列(4.25秒)

limit offset rowsoffsetが大きい場合、効率の問題が発生することが分かっています。

mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | 値 | ソース |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 列セット (15.98 秒)

同じ目的を達成するために、通常は次のように書き直します。

mysql> select * from test a 内部結合 (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | ソース | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
セット5行(0.38秒)

時間の違いは明らかです。

なぜ上記のような結果が表示されるのでしょうか? select * from test where val=4 limit 300000,5;のクエリ プロセスを見てみましょう。

インデックス リーフ ノード データが照会されます。
リーフ ノードの主キー値に基づいて、クラスター化インデックス上のすべての必須フィールド値をクエリします。

次の図のようになります。

上記のように、インデックス ノードを300005回クエリし、クラスター化インデックス データを300005回クエリし、最後に最初の300000結果をフィルターして最後の 5 件を取り出す必要があります。 MySQL 、クラスター化インデックスのデータをクエリするために大量のランダム I/O を費やし、 300000のランダムI/Oによってクエリされたデータは結果セットに表示されません。

誰かが必ずこう尋ねるでしょう: インデックスは最初に使用されるので、最初にインデックス リーフ ノードに沿って必要な最後の 5 つのノードまでクエリを実行し、次にクラスター化インデックス内の実際のデータをクエリするのはなぜですか。これには、次の図のプロセスと同様に、5 つのランダム I/O のみが必要です。

確認済み:

上記の推論を確認するために実際にいくつかの操作を実行してみましょう。

select * from test where val=4 limit 300000 , 5 がクラスター化インデックス上で300005インデックス ノードと300005データ ノードをスキャンすることを証明するには、MySQL に 1 つの SQL でインデックス ノードを介してデータ ノードがクエリされる回数をカウントする方法があるかどうかを知る必要があります。まずHandler_read_*シリーズを試してみましたが、残念ながらどの変数も条件を満たしませんでした。

私はこれを間接的にしか確認できません:

InnoDBにはbuffer poolがあります。データ ページやインデックス ページなど、最近アクセスされたデータ ページが含まれます。したがって、 buffer pool内のデータ ページの数を比較するには、 2 つの SQL ステートメントを実行する必要があります。予測結果では、 select * from test a inner join (select id from test where val=4 limit 300000,5) b>実行した後、 buffer pool内のデータ ページ数はselect * from test where val=4 limit 300000, 5; の対応する数よりもはるかに少なくなります。これは、前者の SQL がデータ ページに 5 回しかアクセスしないのに対し、後者の SQL がデータ ページに300005回アクセスするためです。

val=4 の制限 300000,5 のテストから * を選択

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
空セット (0.04 秒)

現在、 buffer pool内にテスト テーブルに関するデータ ページが存在しないことがわかります。

mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | 値 | ソース |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
セット5列(26.19秒)

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+-----------+
| インデックス名 | カウント(*) |
+------------+-----------+
| プライマリ | 4098 |
| 値 | 208 |
+------------+-----------+
セットに2行(0.04秒)

この時点で、 buffer poolにはテスト テーブルのデータ ページが4098ページ、インデックス ページが 208 ページあることがわかります。

select * from test a inner join (select id from test where val=4 limit 300000,5) b>buffer poolをクリアしてmysql。

mysqladmin シャットダウン
/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
空セット (0.03 秒)

SQL を実行します:

mysql> select * from test a 内部結合 (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | ソース | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
セットに5行(0.09秒)

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+-----------+
| インデックス名 | カウント(*) |
+------------+-----------+
| プライマリ | 5 |
| 値 | 390 |
+------------+-----------+
セットに2行(0.03秒)

2 つの違いは明らかです。最初の SQL は 4098 のデータ ページをbuffer poolにロードしますが、2 番目の SQL は 5 つのデータ ページのみをbuffer pool。私たちの予測通りです。これにより、最初の SQL ステートメントが遅い理由も確認できます。大量の役に立たないデータ行 (300,000) を読み取ってから破棄します。

そして、これは問題を引き起こします。あまりホットではないデータ ページを大量にbuffer poolにロードすると、 buffer pool汚染が発生し、 buffer poolスペースが占有されます。

発生した問題:

再起動のたびにbuffer poolがクリアされるようにするには、 innodb_buffer_pool_dump_at_shutdowninnodb_buffer_pool_load_at_startupオフにする必要があります。これら 2 つのオプションは、データベースのシャットダウン時にバッファー プール データをダンプすることと、データベースの起動時にディスクにバックアップbuffer poolデータをロードすることを制御します。

これで、MySQL で limit を使用するとパフォーマンスに影響する理由に関するこの記事は終了です。MySQL で limit を使用するとパフォーマンスにどのような影響があるかの詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySql ページングで limit+order by を使用する場合のデータ重複の解決策
  • 制限を使用すると、MySQL のページングがどんどん遅くなるのはなぜですか?
  • MySQL 最適化 query_cache_limit パラメータの説明
  • MySQLのorder byとlimitを混在させる際の落とし穴の詳細な説明
  • 大きなオフセットによる MySQL 制限ページングが遅い理由と最適化ソリューション
  • MySQL のソートとページング (order by と limit) と既存の落とし穴
  • MySQL は制限を使用してページング例メソッドを実装します
  • MySQLの制限を使用して大規模なページングの問題を解決する方法
  • MySQLのページング制限のパフォーマンス問題についての簡単な説明
  • MySQL の制限パフォーマンス分析と最適化
  • MySQL クエリにおける LIMIT の大きなオフセットによって引き起こされるパフォーマンス低下の分析

<<:  Zabbix カスタム監視 nginx ステータス実装プロセス

>>:  ブラウザが登録できるイベントの概要

推薦する

mysql8.0.14.zip のインストール中にデータ フォルダを自動的に作成できませんでした。サービスを開始できません。

今日システムを再インストールした後、コンピューターに mysql を再インストールし、ZIP ファイ...

Docker イメージの最適化 (1.16GB から 22.4MB)

目次最適化の第一歩: 軽量ベースイメージの使用第2段階の最適化:多段階構築Docker は、ソフトウ...

Navicat Premiumを使用してMySQLデータベースにリモート接続する方法

新しい接続を作成する側がクライアントに相当し、接続される側がサーバーに相当します。手順は次のとおりで...

JavaScript スネーク実装コード

この記事の例では、参考までに貪欲なスネークを実装するためのJavaScriptの具体的なコードを共有...

nginxディレクトリパスをリダイレクトする方法

ドメイン名に続くパスがデフォルトの Web ディレクトリではなく、ローカル ディスク上の他のディレク...

Windows での MySQL のダウンロード、インストール、設定、使用に関するチュートリアル

MySQLの概要MySQL はリレーショナル データベース管理システムです。データベースは構造化され...

HTMLベースの複数画像アップロードのプレビュー機能を実装

最近、Web ページに複数の画像をアップロードするためのスクリプトを作成しました。これは非常に実用的...

JavaScriptオブジェクト指向について学ぼう

目次JavaScript プロトタイプチェーンオブジェクトプロトタイプトップレベルのプロトタイプOb...

vue シンプルメモ帳開発の詳しい説明

この記事では、参考までにEasy Notepadを実装するためのVueの具体的なコードを紹介します。...

CSS3 は 3D キューブの読み込み効果を作成します

簡単な説明これは CSS3 のクールな 3D キューブのプリロード効果です。この特殊効果は、シンプル...

jQueryアニメーションを理解するのに役立つ記事

目次1. 要素の表示と非表示を制御する show() hide() 2. 要素の透明度を制御する f...

Axios はリクエストをキャンセルし、重複リクエストを回避します

目次起源現状リクエストをキャンセル cancelTokenリクエスト方法の変更重複したリクエストを避...

MySQLで時間別データと最後の時間別データの差をクエリするアイデアの詳細な説明

1. はじめに要件は、特定の時間範囲内で、1 時間ごとのデータと前の 1 時間ごとのデータの差と比率...

jQueryは画像の強調表示を実現します

ページ上の画像を強調表示することは非常に一般的です。ここでは、jQuery を使用して画像を強調表示...

要素 DateTimePicker+vue ポップアップボックスに時間のみが表示される問題を解決する

3つの知識ポイント: 1. CSS子孫セレクターhttps://www.w3school.com.c...