序文 MySQL クエリは select コマンドを使用し、limit および offset パラメータを使用して、指定された範囲のレコードを読み取ることができます。この記事では、オフセットが大きすぎて MySQL クエリのパフォーマンスに影響する理由と、それを最適化する方法について紹介します。 テストデータシートとデータを準備する 1. テーブルを作成する テーブル「メンバー」を作成( `id` int(10) 符号なし NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL COMMENT '名前', `gender` tinyint(3) unsigned NOT NULL COMMENT '性別', 主キー (`id`)、 キー `gender` (`gender`) )ENGINE=InnoDB デフォルト文字セット=utf8; 2. 1,000,000件のレコードを挿入する <?php $pdo = 新しい PDO ("mysql:host=localhost;dbname=user","root",''); ($i=0; $i<1000000; $i++){ $name = substr(md5(time().mt_rand(000,999)),0,10); 性別 = mt_rand(1,2); $sqlstr = "メンバー(名前、性別)に値('".$name."','".$gender."')を挿入します"; $stmt = $pdo->prepare($sqlstr); $stmt->execute(); } ?> mysql> メンバーから count(*) を選択します。 +----------+ | カウント(*) | +----------+ | 1000000 | +----------+ セット内1列(0.23秒) 3. 現在のデータベースバージョン mysql> バージョンを選択します(); +-----------+ | バージョン() | +-----------+ | 5.6.24 | +-----------+ セット内の1行(0.01秒) 大きなオフセットがパフォーマンスに影響を与える理由を分析する 1. オフセットが小さい場合 mysql> メンバーから * を選択し、性別 = 1 を制限 10,1 にします。 +----+------------+--------+ | ID | 名前 | 性別 | +----+------------+--------+ | 26 | 509e279687 | 1 | +----+------------+--------+ セット内の 1 行 (0.00 秒) mysql> メンバーから * を選択して、性別 = 1 の制限を 100,1 にします。 +-----+------------+--------+ | ID | 名前 | 性別 | +-----+------------+--------+ | 211 | 07c4cbca3a | 1 | +-----+------------+--------+ セット内の 1 行 (0.00 秒) mysql> メンバーから * を選択して、性別 = 1 の制限を 1000,1 にします。 +------+------------+---------+ | ID | 名前 | 性別 | +------+------------+---------+ | 1975 | e95b8b6ca1 | 1 | +------+------------+---------+ セット内の 1 行 (0.00 秒) オフセットが小さいとクエリ速度が速くなり、効率が高くなります。 2. 大きなオフセット mysql> メンバーから * を選択して、性別 = 1 の制限を 100000,1 にします。 +--------+------------+---------+ | ID | 名前 | 性別 | +--------+------------+---------+ | 199798 | 540db8c5bc | 1 | +--------+------------+---------+ セット内1列(0.12秒) mysql> メンバーから * を選択し、性別 = 1 を制限 200000,1 にします。 +--------+------------+---------+ | ID | 名前 | 性別 | +--------+------------+---------+ | 399649 | 0b21fec4c6 | 1 | +--------+------------+---------+ セット内1列(0.23秒) mysql> メンバーから * を選択して、性別 = 1 の制限を 300000,1 にします。 +--------+------------+---------+ | ID | 名前 | 性別 | +--------+------------+---------+ | 599465 | f48375bdb8 | 1 | +--------+------------+---------+ セット内1列(0.31秒) オフセットが大きい場合、効率の問題が発生し、オフセットが増加するにつれて、実行効率が低下します。 パフォーマンスに影響を与える理由を分析する 性別=1 の制限 300000,1 のメンバーから * を選択します。 データ テーブルは InnoDB であるため、InnoDB インデックスの構造に応じて、クエリ プロセスは次のようになります。
しかし、セカンダリ インデックスですでにプライマリ キー値が検索されているのに、なぜプライマリ キー インデックスを使用して最初にデータ ブロックを検索し、次にオフセット値に基づいてオフセット処理を実行する必要があるのでしょうか。 主キーインデックスを見つけた後、まずオフセット処理を実行し、300,000 をスキップし、300,001 番目のレコードの主キーインデックスを通じてデータブロックを読み取ると、効率が向上します。 主キーのみをクエリした場合、何が違うのか確認する mysql> メンバーから ID を選択し、性別を 1 に制限します (300000,1)。 +--------+ |id| +--------+ |599465| +--------+ セット内の1行(0.09秒) 明らかに、主キーのみをクエリすると、すべてのフィールドをクエリする場合に比べて実行効率が大幅に向上します。 投機 主キーのみをクエリする セカンダリ インデックスが主キー値を見つけ、クエリは主キーのみを読み取る必要があるため、MySQL は最初にオフセット操作を実行し、その後、後続の主キー インデックスに基づいてデータ ブロックを読み取ります。 すべてのフィールドをクエリする必要がある場合 セカンダリインデックスは主キーの値のみを検索しますが、他のフィールドの値を取得するにはデータブロックを読み取る必要があるためです。したがって、MySQL は最初にデータ ブロックの内容を読み取り、次にオフセット操作を実行し、最後にスキップする必要がある前のデータを破棄して、後続のデータを返します。 確認 InnoDB には、データ ページやインデックス ページなど、最近アクセスされたデータ ページを格納するバッファー プールがあります。 テスト目的で、まず MySQL を再起動してから、バッファ プールの内容を確認します。 mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('primary','gender') and TABLE_NAME like '%member%' group by index_name; 空セット (0.04 秒) 再起動後にデータ ページにアクセスされていないことがわかります。 すべてのフィールドをクエリし、バッファプールの内容を表示します。 mysql> メンバーから * を選択して、性別 = 1 の制限を 300000,1 にします。 +--------+------------+---------+ | ID | 名前 | 性別 | +--------+------------+---------+ | 599465 | f48375bdb8 | 1 | +--------+------------+---------+ セット内1列(0.38秒) mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('primary','gender') and TABLE_NAME like '%member%' group by index_name; +------------+-----------+ | インデックス名 | カウント(*) | +------------+-----------+ | 性別 | 261 | | プライマリ | 1385 | +------------+-----------+ セットに2行(0.06秒) この時点で、バッファー プールにはメンバー テーブルのデータ ページが 1385 個、インデックス ページが 261 個あることがわかります。 MySQLを再起動してバッファプールをクリアし、主キーのみをクエリするテストを続行します。 mysql> メンバーから ID を選択し、性別を 1 に制限します (300000,1)。 +--------+ |id| +--------+ |599465| +--------+ セット内の1行(0.08秒) mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('primary','gender') and TABLE_NAME like '%member%' group by index_name; +------------+-----------+ | インデックス名 | カウント(*) | +------------+-----------+ | 性別 | 263 | | プライマリー | 13 | +------------+-----------+ セットに2行(0.04秒) この時点で、バッファー プールにはメンバー テーブルのデータ ページが 13 個、インデックス ページが 263 個しかないことがわかります。したがって、主キー インデックスを介してデータ ブロックにアクセスする複数の I/O 操作が削減され、実行効率が向上します。 したがって、オフセットが大きすぎて MySQL クエリ時のパフォーマンスに影響を与える原因は、主キーインデックスを介してデータブロックに複数回アクセスする I/O 操作であることが確認できます。 (この問題が発生するのは InnoDB のみであり、MYISAM インデックス構造は InnoDB とは異なることに注意してください。セカンダリ インデックスはすべてデータ ブロックを直接ポイントするため、このような問題は発生しません)。 InnoDB と MyISAM エンジンのインデックス構造の比較 ここに写真の説明を記入してください 最適化手法 上記の分析に基づいて、すべてのフィールドをクエリすると、主キー インデックスによるデータ ブロックへの複数回のアクセスによって I/O 操作が発生することがわかります。 したがって、最初にオフセット主キーを見つけ、次に主キー インデックスに基づいてデータ ブロックのすべての内容を照会して最適化を実現します。 mysql> メンバーから a.* を内部結合として選択します (メンバーから id を選択し、性別 = 1、制限 300000,1)、b として a.id = b.id で選択します。 +--------+------------+---------+ | ID | 名前 | 性別 | +--------+------------+---------+ | 599465 | f48375bdb8 | 1 | +--------+------------+---------+ セット内の1行(0.08秒) 付録: MYSQL の制限、オフセットの違い 選択 キーワード から キーワードランク どこ 広告id='59' 並び替え キーワード 制限 2 オフセット 1; たとえば、この SQL ステートメントでは、制限の後に 2 つのレコードが続き、オフセットの後に最初のレコードが続きます。 選択 キーワード から キーワードランク どこ 広告id='59' 注文する キーワード 制限 2,1; この SQL では、制限に従って 2 番目の項目から読み取り、1 つの情報を読み取ります。 これら2つを混同しないでください。 要約する 上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。 以下もご興味があるかもしれません:
|
<<: JSはreduce()メソッドを使用してツリー構造データを処理します
>>: Linux 環境の Apache サーバーでセカンダリドメイン名を設定する方法の詳細な説明
インターネットで見つけた方法は効果的ですinclude によって導入されたフッター ファイルとヘッダ...
目次概要Canvas API: グラフィックスの描画パス線種矩形アーク文章グラデーションと画像の塗り...
導入react-i18next は、 i18nextをベースにした強力な国際化フレームワークです。 ...
HTML を学ぶメリットは何ですか? 1: ウェブサイトやブログのウェブ構造を簡単に変更できます。...
1. nginxをダウンロードする [root@localhost my.Shells]# dock...
Vue でのコードの再利用により、mixnis が提供されます。テンプレートの再利用により、スロット...
MySQL 5.7 をインストールするには 2 つの方法があります。1 つはインストーラをダウンロー...
序文Oracle や SQL Server などのデータベースには、ストレージ エンジンが 1 つだ...
テーブル構造は次のとおりです。 id varchar(32) 情報JSONデータ: id = 1 i...
問題を見つける今日はTomcatのソースコードを勉強するつもりなので、公式サイトからTomcatのソ...
CSS3 アニメーション トランジションを使用して、リンクの上にマウスを移動すると小さなポップアップ...
黄金律常に同じコーディング標準セットに従ってください。同じプロジェクトに何人の人が関わっているかに関...
序文デフォルトでは、MySQL はデータベース クエリ データをキャッシュするために大きなメモリ ブ...
1. はじめにVagrant は、仮想マシン (VirtualBox) を構築および管理するためのツ...
Redisイメージをダウンロードする docker pull yyyyttttwww/redis を...