序文
私たちユーザーにとってMySQL
、MySQL
それは実際にはソフトウェアの一部であり、最もよく使用するものです查询功能
。クエリがどのように実行されるかさえわからない場合は、何を最適化すればよいのか、実際のテクノロジーをマスターする時期が来ましたDBA
。慢查询语句
1. データの準備
前の記事で、というモジュールMySQL Server
があること查询优化器
がわかりました。クエリ ステートメントが解析された後、最適化のためにクエリ オプティマイザに渡されます。最適化の結果は、いわゆる実行プランを生成します。この実行プランには、クエリにどのインデックスを使用するか、テーブル間の接続シーケンスは何か、そして最後に、実行プランの手順に従ってストレージ エンジンが提供するメソッドが呼び出され、実際にクエリが実行されること、およびクエリの結果が示されます。ユーザーに返されます。ただし、クエリ最適化のトピックは少し大きく、実行方法を学ぶ前に使い方を学ばなければなりません。そのため、この章ではまず、MySQL が単一テーブル クエリ (つまり、単一テーブル クエリ) をどのように実行するかを見てみましょう。 、from ステートメントの後ろにはテーブルが 1 つだけあり、最も単純な種類のクエリです~)。ただし、強調すべき点の 1 つは、この章を学習する前に、レコード構造、データ ページ構造、およびインデックスに関する前の部分を読む必要があるということです。これらの内容を完全に習得していることが保証できない場合、この章は適していません。
スムーズに学習するために、まず表を作成します。
mysql> USE testdb;
mysql> create table demo8 (
id int not null auto_increment,
key1 varchar(100),
key2 int,
key3 varchar(100),
key_part1 varchar(100),
key_part2 varchar(100),
key_part3 varchar(100),
common_field varchar(100),
primary key (id),
key idx_key1 (key1),
unique key idx_key2 (key2),
key idx_key3 (key3),
key idx_key_part(key_part1, key_part2, key_part3));
合計 1 つのクラスター化 (主キー) インデックスと 4 つのセカンダリ インデックスが、demo8 テーブルに対して作成されました。
- id 列用に作成されたクラスター化インデックス。
- key1 列用に作成されたセカンダリ インデックス。
- key2 列用に作成された一意のセカンダリ インデックス。
- key3 列用に作成されたセカンダリ インデックス。
- key_part1、key_part2、key_part3 列に対して作成された複合 (結合) セカンダリ インデックス。
次に、このテーブルに 20,000 レコードを挿入し、id 列を除くすべての列にランダムな値を挿入する必要があります。
mysql> delimiter //
create procedure demo8data()
begin
declare i int;
set i=0;
while i<20000 do
insert into demo8(key1,key2,key3,key_part1,key_part2,key_part3,common_field) values(substring(md5(rand()),1,2),i+1,substring(md5(rand()),1,3),substring(md5(rand()),1,4),substring(md5(rand()),1,5),substring(md5(rand()),1,6),substring(md5(rand()),1,7));
set i=i+1;
end while;
end;
//
delimiter ;
mysql> call demo8data();
2. 単一テーブルアクセス方式
2.1 アクセス方式の概念
小学生の頃に辞書を引いた経験は誰しもあると思いますが、語彙力がある程度のレベルに達していないうちは、見たことのない言葉の意味を知りたければ辞書で調べる必要があります。辞書。通常の状況では、まず辞書ディレクトリに移動して、対応するピンインまたは中国語の部首を見つけ、単語のページ番号を見つけてから、対応するページ番号に直接アクセスして、対応する定義を表示します。暇なときに何百ページもある辞書を最初のページから最後のページまで探して、やっと見つけられる、という状況もあります。どちらの方法でも望む結果を得ることができますが、費やす時間とエネルギーは大きく異なります。MySQL でも同様で、クエリデータを高速化するために B+ ツリーインデックスという概念が提案されています。しかし、場合によっては、すべてのデータをクエリしたい場合、結果を得るためにすべてのデータ ページを 1 行ずつ、1 ページずつ走査する必要があります。
単一テーブルのクエリの場合、MySQL クエリの実行方法は大きく次の 2 種類に分けられます。
2.1.1 フルテーブルスキャンを使用したクエリ
この方法は上で述べた通りで、レコードを行ごと、ページごとに走査し、検索条件を満たすレコードを結果セットに追加するだけで終わりです。この方法はニーズを満たすことができますが、効率が最も低いことは間違いありません。
2.1.2 インデックスを使用したクエリ
フルテーブルスキャン方式を使用してクエリを直接実行するには、多くのレコードを走査する必要があり、コストが非常に高くなる可能性があります。辞書ディレクトリを通じて漢字を検索するのと同じように、MySQL クエリ ステートメントの検索条件でインデックスを使用できる場合は、インデックスを直接使用してクエリを実行すると、クエリの実行時間が短縮される可能性があります。クエリを実行するためにインデックスが使用される方法は、多くのカテゴリに分類できます。
- 主キーまたは一意のセカンダリ インデックスに対する等価クエリ
- 共通セカンダリインデックスに対する等価クエリ
- インデックス付き列の範囲によるクエリ
- インデックス全体を直接スキャンすることにより
まとめ
MySQL がクエリ ステートメントを実行する方法は、アクセス メソッドまたはアクセス タイプと呼ばれます。同じクエリ ステートメントをさまざまなアクセス方法で実行すると、最終的なクエリ結果は同じでも、実行効率は大きく異なります。
2.2 定数
主キー列でレコードを検索します。
mysql> select * from demo8 where id=9999;
+------+------+------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+------+------+------+------+-----------+-----------+-----------+--------------+
| 9999 | 34 | 9999 | 6c7 | 1823 | 24955 | 5deed4 | 3aebe82 |
+------+------+------+------+-----------+-----------+-----------+--------------+
1 row in set (0.00 sec)
MySQL B+ ツリー インデックスのクラスター化インデックス B+ ツリーの構造をまだ覚えていますか? リーフ (Leaf) ノードには完全なレコードが格納され、B+ ツリーのリーフ (Leaf) ノード内のレコードはプライマリの値に従ってソートされます。キー ID 列の小さいものから大きいものまで。B+ ツリーはもともと短く太く、一意で順序付けられ、空ではない属性を備えているため、主キー値に従ってレコードを検索する速度が非常に高速です。同様に、一意のセカンダリ インデックス列に基づいてレコードを非常に高速に検索できます。
mysql> select * from demo8 where key2=8888;
+------+------+------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+------+------+------+------+-----------+-----------+-----------+--------------+
| 8888 | 12 | 8888 | fc9 | 7810 | 1c7ed | 5d6dbc | adbea8c |
+------+------+------+------+-----------+-----------+-----------+--------------+
1 row in set (0.00 sec)
以前の記事の知識に基づいて、このクエリの実行は 2 つのステップに分かれています。
- 最初のステップは、key2 列と定数の間の等価比較条件に従って、idx_key2 に対応する B+ ツリー インデックスからセカンダリ インデックス レコードを特定することです。
- 2 番目のステップでは、レコードの ID 値に従ってクラスター化インデックスから完全なユーザー レコードが取得されます。
MySQL では、主キーまたは一意のセカンダリ インデックス カラムと定数との同等の比較を通じてレコードを非常に高速に見つけることができるため、主キーまたは一意のセカンダリ インデックス カラムを介してレコードを見つけるためのアクセス方法が定義されています。 as: const は一定レベルを意味し、コストは無視できます。
ただし、この const アクセス方法は、主キー列または一意のセカンダリ インデックス列が定数と比較されて等しい場合にのみ有効です。主キーまたは一意のセカンダリ インデックスが複数の列で構成されている場合、インデックス内の各インデックスには列が必要です。等価性について定数と比較する必要があり、この const アクセス メソッドは有効です (これは、インデックス内のすべての列が等価性について比較される場合にのみ、唯一のレコードを見つけることができるためです)。
一意のセカンダリ インデックスの場合、列が NULL 値であることをクエリする場合は特殊です。
mysql> select * from demo8 where key2 is null;
唯一のセカンダリインデックス列は NULL 値の数を制限しないため、上記のステートメントは複数のレコードにアクセスする可能性があります。上記のステートメントは const アクセスメソッドを使用して実行できません。アクセスメソッドについては、すぐ下で説明します。
2.3 参照
通常のセカンダリ インデックス列は、定数と等しいかどうか比較されます。
mysql> select * from demo8 where key1 = 'd9';
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| 59 | d9 | 59 | b7a | 041b | 5b1cf | e342ac | e103738 |
| 182 | d9 | 182 | 8bf | 2b3c | 08b7c | a63ed0 | 40f2c52 |
| 401 | d9 | 401 | 137 | adbd | dafba | 581313 | ba72bf5 |
| 2114 | d9 | 2114 | d8b | bf2a | 117ae | 69de3d | f5467a5 |
| 2758 | d9 | 2758 | 2f7 | a159 | e3707 | f60f38 | 795ec06 |
| 3823 | d9 | 3823 | 682 | 347e | f6195 | 6faa0d | 5e55f78 |
| 4351 | d9 | 4351 | e92 | f3b4 | a159e | d3e013 | e28ca48 |
| 5138 | d9 | 5138 | b41 | 1b10 | b9605 | cbe517 | b267144 |
| 5539 | d9 | 5539 | da1 | d30d | c59b1 | 0c5d79 | ae57b7d |
| 5604 | d9 | 5604 | ddc | f0b0 | 00dbf | f93c0e | 3218cff |
| 6050 | d9 | 6050 | 64e | 22a4 | 69e69 | 7284ba | 4a5b7d5 |
| 6147 | d9 | 6147 | 529 | cd38 | 71855 | 434168 | a426cbe |
| 6428 | d9 | 6428 | a38 | c00f | 9f710 | 9fb7c5 | a722b51 |
| 6456 | d9 | 6456 | eb7 | d208 | 30539 | ee3ae4 | a6c4870 |
| 6473 | d9 | 6473 | c15 | da29 | cc897 | 1e35c3 | 4b5f135 |
| 6860 | d9 | 6860 | b01 | bad8 | 4e3a9 | e83331 | 0cd3b9d |
| 7257 | d9 | 7257 | fa6 | d537 | a4afe | bbc5d8 | e11e937 |
| 7333 | d9 | 7333 | a97 | 5532 | 64097 | cb5d16 | 7e43077 |
| 7867 | d9 | 7867 | 3d7 | b341 | 0b0bb | 7df721 | 8c64142 |
| 8265 | d9 | 8265 | a16 | 120b | 9d372 | c17ce4 | c481ace |
| 8371 | d9 | 8371 | 5be | 7924 | 313f7 | 293487 | cb52072 |
| 8738 | d9 | 8738 | c05 | 7123 | b61b1 | c8d819 | e310cbf |
| 9005 | d9 | 9005 | 44e | e857 | 4075c | 8460a0 | 409cb1d |
| 9006 | d9 | 9006 | d8c | 8c2b | ed54f | 3b8bfd | 268fcce |
| 9362 | d9 | 9362 | 5cb | 9d70 | 05937 | 1b70d2 | a866a32 |
| 9449 | d9 | 9449 | ab8 | f9c6 | c1917 | 5ffe25 | ff88471 |
| 10146 | d9 | 10146 | 07f | 31a7 | c30c4 | 7c2e48 | 6c5c562 |
| 10197 | d9 | 10197 | 85a | 4796 | e5ff9 | d12af4 | 20be699 |
| 10223 | d9 | 10223 | 94b | c57e | adfb6 | b93c19 | a7c944b |
| 10285 | d9 | 10285 | 9ab | f33d | 69e5c | 35a651 | 0953db7 |
| 10621 | d9 | 10621 | a29 | a92b | fbf80 | 83f1e2 | d167770 |
| 11133 | d9 | 11133 | 560 | 97af | 35f38 | ceb1b9 | 6e89ca8 |
| 11265 | d9 | 11265 | fcc | e7d7 | 0243e | b52571 | 89ea417 |
| 11557 | d9 | 11557 | 1c0 | 7f66 | 0898f | d41cfc | e759975 |
| 11614 | d9 | 11614 | de5 | 00f7 | fb3b3 | 93dc1a | bbe8993 |
| 11672 | d9 | 11672 | f3f | 9fe4 | da2dd | 82f711 | 436f3d4 |
| 12477 | d9 | 12477 | d58 | 0613 | 1df6d | 40999a | b748cd2 |
| 13789 | d9 | 13789 | 67b | 5b30 | ab2f3 | 89f0ec | 9e2d255 |
| 14050 | d9 | 14050 | 537 | bbdc | 5e87e | 4ac153 | 0346558 |
| 14363 | d9 | 14363 | 2ac | 33f3 | e2b82 | 7e55c1 | 45ee579 |
| 14444 | d9 | 14444 | e47 | 6319 | 851b7 | 1d4c57 | e17a95b |
| 14635 | d9 | 14635 | 16a | 4d83 | 52b33 | 376017 | c853bc0 |
| 14646 | d9 | 14646 | 202 | 6fdd | f2486 | 9900f3 | c29d0d6 |
| 15298 | d9 | 15298 | 074 | a7ee | 6bc1d | e96458 | 723b0f8 |
| 15489 | d9 | 15489 | 514 | 0bdc | fb94c | db5ce8 | 63797e8 |
| 16895 | d9 | 16895 | 4aa | 921c | 00b9e | f07907 | bce779f |
| 17587 | d9 | 17587 | 6aa | 621b | d521f | a6c5ad | 45fac89 |
| 18151 | d9 | 18151 | 87d | cd74 | f7135 | 47d900 | 211303e |
| 18255 | d9 | 18255 | 4dc | b9e7 | 99bf2 | 55d0eb | 3e6ce6c |
| 18490 | d9 | 18490 | 6a2 | f0ff | 85e86 | ed9bb8 | dca2cb4 |
| 18872 | d9 | 18872 | 404 | eeee | 001c7 | 0e846d | fae0876 |
| 19018 | d9 | 19018 | 142 | 80d7 | 2b9fd | 77be32 | d6d8398 |
| 19228 | d9 | 19228 | a5b | a125 | 795fa | 108159 | 65acbf5 |
| 19537 | d9 | 19537 | 1ca | 016a | 3df13 | 3f5b9c | 720de00 |
| 19940 | d9 | 19940 | 95c | 6150 | 2696d | 3f89b8 | d37d43a |
| 19945 | d9 | 19945 | 538 | 6378 | a20a9 | 2b7b00 | 1865f1c |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
56 rows in set (0.00 sec)
通常のセカンダリ インデックスはインデックス列の値の一意性を制限しないため、複数の対応するレコードを検索することができます (この例では、条件を満たす合計 56 行が一致しました)。つまり、セカンダリ インデックスを使用します。クエリを実行するコストは、同等の値と一致するセカンダリ インデックス レコードの数によって異なります。一致するレコードが少ない場合でも、テーブルに戻るコストは比較的低いため、MySQL はクエリの実行にテーブル全体のスキャンではなくインデックスの使用を選択する場合があります。MySQL は、この検索条件をセカンダリ インデックスのカラムと定数相当値の比較とみなして、セカンダリ インデックスを使用してクエリを実行するアクセス メソッドを ref と呼びます。
通常のセカンダリ インデックスの場合、主キーや一意のセカンダリ インデックスのように最大 1 つのレコードのみを照合するのではなく、インデックス列の等価比較の後に複数の連続するレコードが照合される可能性があるため、この ref アクセスの方法は少し劣ります。 const ですが、二次インデックスの等価物の比較で一致するレコードの数が少ない場合でも効率は非常に高くなります (一致する二次インデックスのレコードが多すぎると、テーブルに戻るコストが高くなりすぎます)。
次の 2 つの状況に注意する必要があります。
- セカンダリ インデックス列の値が NULL の場合: 共通セカンダリ インデックスであっても一意のセカンダリ インデックスであっても、インデックス列に含まれる NULL 値の数に制限はないため、キー IS NULL 形式を使用します。検索条件では、最大でも ref のアクセサー メソッドのみを使用できます。const アクセサー メソッドは使用できません。
- 複数のインデックス列を含むセカンダリ インデックスの場合、左端の連続インデックス列が定数と同等の比較である限り、ref アクセス メソッドを使用できます。
idx_key_part(key_part1, key_part2, key_part3)
mysql> select * from demo8 where key_part1='6378';
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| 19945 | d9 | 19945 | 538 | 6378 | a20a9 | 2b7b00 | 1865f1c |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
1 row in set (0.00 sec)
mysql> select * from demo8 where key_part1='6378' and key_part2='a20a9';
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| 19945 | d9 | 19945 | 538 | 6378 | a20a9 | 2b7b00 | 1865f1c |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
1 row in set (0.00 sec)
mysql> select * from demo8 where key_part1='6378' and key_part2='a20a9' and key_part3='2b7b00';
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
| 19945 | d9 | 19945 | 538 | 6378 | a20a9 | 2b7b00 | 1865f1c |
+-------+------+-------+------+-----------+-----------+-----------+--------------+
1 row in set (0.00 sec)
- ただし、左端の連続するインデックス列がすべて等しい値比較ではない場合、そのアクセス メソッドは ref を呼び出すことができません。
mysql> select * from demo8 where key_part1='6378' and key_part2>'a20a9';
Empty set (0.00 sec)
2.4 ref_or_null
副次インデックス列の値が特定の定数と等しいレコードを検索し、値が NULL であるレコードも検索したい
mysql> select * from demo8 where key1 = 'd9' or key is null;
フルテーブルスキャンではなくセカンダリインデックスを使用してクエリが実行される場合、このタイプのクエリで使用されるアクセス方法は ref_or_null と呼ばれます。これは、まず idx_key1 インデックスに対応する B+ ツリーから key1 IS NULL および key1 = 'ef' の 2 つの連続するレコード範囲を検索し、次にテーブルに戻ってこれらの ID 値に従って完全なユーザー レコードを検索することと同じです。セカンダリ インデックス レコード。
2.5レンジ
前に紹介したいくつかのアクセス方法は、インデックス列を特定の定数値と比較する場合にのみ使用できます (ref_or_null はかなり特殊で、NULL の値も計算されます)。場合によっては、より複雑な検索条件に直面することがあります。
mysql> select * from demo8 where key2 in (5555,6666) or (key2>=1234 and key2<=1235);
+------+------+------+------+-----------+-----------+-----------+--------------+
| id | key1 | key2 | key3 | key_part1 | key_part2 | key_part3 | common_field |
+------+------+------+------+-----------+-----------+-----------+--------------+
| 1234 | 67 | 1234 | a2d | 2779 | 18191 | 96a5b2 | 86c5afa |
| 1235 | 6b | 1235 | c48 | 43b4 | 0e1d1 | 27f9a0 | 1c17810 |
| 5555 | 0b | 5555 | dc2 | 6b61 | dac52 | a0451f | 187011e |
| 6666 | 00 | 6666 | 9c3 | 99f8 | d22de | 283e92 | 656f2f1 |
+------+------+------+------+-----------+-----------+-----------+--------------+
4 rows in set (0.00 sec)
このクエリはフルテーブルスキャンでも実行できますが、セカンダリインデックス+テーブルリターンでも実行できます。セカンダリインデックス+テーブルリターンでクエリを実行する場合、このときの検索条件はインデックスカラムだけでなく必要となります。は定数の同等の値と一致しますが、インデックス列は特定の値の範囲と一致する必要があります。このクエリでは、key2 列の値が次の 3 つの範囲のいずれかに一致する限り、一致は成功します。
- key2の値は5555です
- key2の値は6666です
- key2 の値は 1234 ~ 1235 です。
MySQL は、範囲一致のインデックスを使用してこのアクセス メソッドを呼び出します。range
2.6 インデックス
mysql> select key_part1,key_part2,key_part3 from demo8 where key_part2 = 'd22de';
+-----------+-----------+-----------+
| key_part1 | key_part2 | key_part3 |
+-----------+-----------+-----------+
| 99f8 | d22de | 283e92 |
+-----------+-----------+-----------+
1 row in set (0.01 sec)
key_part2 は結合インデックス idx_key_part の左端のインデックス列ではないため、ref または range アクセス メソッドを使用してこのステートメントを実行することはできません。ただし、このクエリは次の 2 つの条件を満たしています。
- そのクエリ リストには key_part1、key_part2、key_part3 の 3 つの列しかなく、インデックス idx_key_part にはこれら 3 つの列が含まれています。
- 検索条件には key_part2 列のみがあり、この列もインデックス idx_key_part に含まれます
idx_key_part インデックスのリーフ ノード レコードを走査することで key_part2 = 'd22de' 条件を直接比較し、正常に一致したセカンダリ インデックス レコードの key_part1、key_part2、および key_part3 列の値を結果セットに直接追加できます。セカンダリ インデックス レコードはクラスター化インデックス レコードよりもはるかに小さいため (クラスター化インデックス レコードにはすべてのユーザー定義列といわゆる非表示列が格納されますが、セカンダリ インデックス レコードにはインデックス列と主キーのみが格納される必要があります)、このプロセスでは実行する必要はありません。テーブルの戻り操作のため、セカンダリ インデックスを直接走査するコストは、クラスター化インデックスを直接走査するよりもはるかに小さくなります。セカンダリ インデックス レコードを走査するこのメソッドは、次のように呼ばれます。index
2.7すべて
mysql> select * from demo8;
この SQL ステートメントと同じように、すべてのデータをクエリします。このクエリ実行メソッドはフル テーブル スキャンです。InnoDB テーブルの場合、クラスター化インデックスの直接スキャンです。フル テーブル スキャンを使用してクエリを実行するこのメソッドは、次のように呼ばれます。
3. 注意すべき事項
3.1 セカンダリインデックス + リターンテーブルを確認する
一般に、次のステートメントなどのクエリの実行に使用できるセカンダリ インデックスは 1 つだけです。
mysql> select * from demo8 where key1='00' and key2>15544;
クエリ オプティマイザーは、このクエリ内の 2 つの検索条件を認識します。
- キー1='00'
- キー2>15544
オプティマイザは通常、demo8 テーブルの統計データに基づいて、対応するセカンダリ インデックスでクエリおよびスキャンする行数が少ない条件を判断し、対応するセカンダリ インデックスでクエリするスキャン行数が少ない条件を選択します。次に、セカンダリ インデックスからクエリされた結果をテーブルに返して完全なユーザー レコードを取得し、残りの where 条件に従ってレコードをフィルター処理します。オプティマイザがクエリに idx_key1 インデックスを使用することを決定したと仮定すると、クエリ プロセス全体は次の 2 つのステップに分割できます。
- ステップ 1: セカンダリ インデックスを使用してレコードを検索します。条件 key1 = '00' に従って、idx_key1 インデックスによって表される B+ ツリーから対応するセカンダリ インデックス レコードを見つけます。
- ステップ 2: 前のステップで見つかったレコードの主キー値に従ってテーブルに戻ります。つまり、クラスター化インデックスで対応する完全なユーザー レコードを見つけ、条件キー 2 に従って完全なユーザー レコードのフィルタリングを続けます。 >15544。最終的にフィルタ条件を満たすレコードをユーザーに返します
セカンダリ インデックスのノード内のレコードにはインデックス列と主キーのみが含まれるため、手順 1 で idx_key1 インデックスを使用してクエリを実行する場合は key1 列に関連する検索条件のみが使用され、その他の条件 (key2 > など) が使用されます。 9988 はステップ 1 では使用されません。ステップ 2 でテーブルを返す操作が完了した後でのみ、完全なユーザー レコードのフィルタリングを続けることができます。
ヒント:
ここで話しているのは一般的な状況であることに注意してください。一般に、クエリの実行には 1 つのセカンダリ インデックスのみが使用されます。
3.2 レンジアクセス方式で使用するレンジ間隔を明確にする
B+ ツリー インデックスの場合、インデックス列と定数に =、<=>、in、not in、is null、is not null、>、<、>=、<=、 between、!= (等しくない) を使用する限り、 <> として記述するか、同様の演算子で接続すると、いわゆる間隔を生成できます。
ヒント:
- like 演算子は特別であり、完全な文字列と一致する場合、または文字列のプレフィックスと一致する場合にのみインデックスを使用できます。
- in 演算子の効果は、
=
複数の同等の一致演算子or
間の接続と同じです。つまり、複数の単一点間隔が生成されます。たとえば、
次の 2 つのステートメントの効果は同じです。 where key2 in (1222, 1333);
select * from Demon8 where key2 = 1222 または key2 = 1333;
ただし、通常の作業では、クエリの where 句に多数の小さな検索条件が含まれる場合があり、これらの検索条件は and または or 演算子を使用して接続する必要があります。
- A と B、A と B の両方が true、式全体が true
- A または B、A または B のいずれかが true の場合、式全体が true になります
範囲アクセス方式を使用してクエリ ステートメントを実行する場合、重要な点は、クエリに使用できるインデックスと、これらのインデックスに対応する範囲間隔を見つけることです。次の 2 つの場合に、and or or で構成される複雑な検索条件から正しい範囲間隔を抽出する方法を見てみましょう。
3.2.1 すべての検索条件でインデックスを使用可能
mysql> select * from demo8 where key2 > 2222 and key2 > 3333;
このクエリのすべての検索条件は key2 を使用できます。つまり、各検索条件は idx_key2 の範囲間隔に対応します。これら 2 つの小さな検索条件は AND を使用して接続されます。つまり、2 つの範囲間隔の交差部分が取得されます。key2 > 2222 と key2 > 3333 の共通部分は当然 key2 > 3333 です。 idx_key2 を使用した上記のクエリの範囲は (3333, +∞) です。
そうである場合、または
mysql> select * from demo8 where key2 > 2222 or key2 > 3333;
または、各範囲間隔の和集合を取得する必要があることを意味します。key2 > 2222 と key2 > 3333 の和集合は key2 > 2222 です。上記のクエリで idx_key2 を使用した範囲間隔は (2222, +∞) です。
3.2.2 一部の検索条件ではインデックスを使用できません
mysql> select * from demo8 where key2 > 2222 AND common_field = '039cb00';
このクエリ文で使用できるインデックスは idx_key2 のみであり、idx_key2 のセカンダリ インデックスのレコードには common_field フィールドが含まれていないため、セカンダリ インデックスを使用する段階では common_field = '039cb00' の条件は使用されません。レコードを検索するための idx_key2。この条件は、完全なユーザー レコードを取得するためにテーブルに戻った後に使用され、範囲間隔はレコードをフェッチするためのインデックスで提案されている概念のためのものであるため、common_field = '039cb00' の条件は必要ありません。インデックスの範囲間隔を決定するときは、該当するインデックスを使用しない検索条件を true に置き換えるだけで済みます (インデックスを使用しない検索条件を true に置き換えます。これらの条件をインデックスの検索に使用するつもりはありません。したがって、インデックス内のレコードがこれらの条件を満たすかどうかに関係なく、後でテーブルに戻るときにそれらを選択してフィルターに使用します)。
mysql> select * from demo8 where key2 > 2222 AND true;
簡略化
mysql> select * from demo8 where key2 > 2222;
このことから、idx_key2 の使用範囲は (2222, +∞) であることがわかります。同様に、 or を使用した状況も次のように取得できます。
mysql> select * from demo8 where key2 > 2222 or common_field = '039cb00';
mysql> select * from demo8 where key2 > 2222 or true;
mysql> select * from demo8 where true;
これは、クエリを実行するために idx_key2 を使用する必要がある場合、対応する範囲は (-∞, +∞) であること、つまり、セカンダリ インデックスのすべてのレコードをテーブルに返す必要があることも示しています。直接の全テーブル スキャンよりも優れています。つまり、インデクスを使用する検索条件とインデクスを使用しない検索条件をorで接続した場合、インデクスは使用できません。
3.2.3 複雑な検索条件で範囲一致区間を求める
mysql> select * from demo8
where (key1 > 'ed' and key2 = 66 )
or (key1 < 'zc' and key1 > 'zz')
or (key1 like '%33' and key1 > 'fa' and (key2 < 7777 or common_field = '97d435e')) ;
このような複雑な条件の SQL を見ても慌てず、ゆっくり分析してみましょう
ステップ 1: まず、where 句の検索条件にどの列が含まれているか、またどの列がインデックスを使用する可能性があるかを確認します。
このクエリの検索条件には key1、key2、common_field の 3 つの列が含まれており、key1 列には共通セカンダリ インデックス idx_key1 があり、key2 列には一意のセカンダリ インデックス idx_key2 があります。
ステップ 2: 使用される可能性のあるインデックスについて、その範囲間隔を分析する
ステップ 3: idx_key1 を使用してクエリを実行するか、上記の方法を使用して、インデックスを使用しない検索条件を一時的に削除するとします。
(key1 > 'ed' and true ) or(key1 < 'zc' and key1 > 'zz') or(true and key1 > 'fa' and (true or true))
簡素化を続ける
(key1 > 'ed') OR(key1 < 'zc' AND key1 > 'zz') OR(key1 > 'fa')
ステップ 4: 常に true または false となる条件を置き換える
mysql> select 'zc' > 'zz';
+-------------+
| 'zc' > 'zz' |
+-------------+
| 0 |
+-------------+
1 row in set (0.00 sec)
結果は 0 (偽) で、'zc' は 'zz' より小さいです。key1 < 'zc' AND key1 > 'zz' の一致は常に false であるため、上記の検索条件は次のように記述できます。
(key1 > 'ed') OR (key1 > 'fa')
引き続き間隔を簡素化します
mysql> select 'ed' > 'fa';
+-------------+
| 'ed' > 'fa' |
+-------------+
| 0 |
+-------------+
1 row in set (0.00 sec)
key1 > 'ed' と key1 > 'fa' の間の or 演算子が接続に使用されます。これは共用体を取ることを意味するため、最終結果が簡略化される間隔は key1 > 'ed' になります。つまり、上記の複雑な検索条件のクエリ ステートメントが idx_key1 インデックスを使用してクエリを実行する場合、key1 > 'ed' を満たすすべてのセカンダリ インデックス レコードを抽出し、その ID を持つテーブルに戻る必要があります。これらのレコードを抽出して完全なユーザー レコードを取得し、他の検索基準を使用してフィルタリングします。
ステップ 5: idx_key2 を使用してクエリを実行すると仮定し、インデックスを使用しない検索条件を一時的に trueE 条件に置き換える必要があり、key1 と common_field に関連する検索条件を置き換える必要があります。
(true and key2 = 66 ) or(true and true) or(true and true and (key2 < 7777 or true))
key2 < 7777 OR true の結果は true です。簡略化を続けます
key2 = 66 or true
単純化を続ける: true
この結果は、idx_key2 インデックスを使用してクエリ ステートメントを実行する場合は、idx_key2 セカンダリ インデックスのすべてのレコードをスキャンしてからテーブルに戻る必要があることを意味します。idx_key1 セカンダリ インデックスを使用する場合と比較して、ゲインはゲインを上回ります。 、2 つのメソッドの比較結果は idx_key2 インデックスとして使用されません。
4. インデックスのマージ
MySQL には、多くの最適化機能が公式に組み込まれていますが、それを有効にする必要があるかどうかは、手動で設定する必要があります。
mysql> show variables like 'optimizer_switch'\g
*************************** 1. row ***************************
variable_name: optimizer_switch
value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,hypergraph_optimizer=off,derived_condition_pushdown=on
1 row in set (0.01 sec)
簡単に説明しましょう:
- Index_merge=on (インデックスのマージ)
- Index_merge_union=on (ユニオン インデックスのマージ - 非クラスター化インデックスによって取得された ID 値のユニオン)
- Index_merge_sort_union=on (ソートとユニオンのインデックスのマージ - 非クラスター化インデックスによって取得された ID 値が最初にソートされます - ユニオンを取得します)
- Index_merge_intersection=on (交差インデックスのマージ - 非クラスター化インデックスによって取得された ID 値の交差)
- Engine_condition_pushdown=on (エンジン条件プッシュダウン - NDB エンジンにのみ使用されます。有効にすると、WHERE 条件に従ってフィルタリングされたデータが処理のために SQL ノードに送信され、すべてのデータ ノードのデータが SQL に送信されるようになります。処理用のノード。)
- Index_condition_pushdown=on (インデックス条件プッシュダウン - ICP)
- mrr=on (マルチレンジ読み取り-MRR - この最適化の主な目的は、可能な限りシーケンシャルなディスク読み取りを使用することです)
- mrr_cost_based=on (コストベースの選択 - 計算が MRR を使用したコスト計算/判断消費に基づくかどうか)
- block_nested_loop=on (ブロックベースのネストされたループ結合 - BNL)
- atched_key_access=off (BKA - インデックスネストループ結合 (NLJ) アルゴリズムの最適化)
- 実体化=オン (実体化)
- subquery_materialization_cost_based=on (サブクエリの実体化のコスト計算を有効にするかどうか)
- semijoin=on (セミジョイン)
- loosescan=on (セミジョイン - ルーズスキャン)
- firstmatch=on (セミ結合 - 最初の一致)
- Duplicateweedout=on (半結合 - 重複値の削除)
- use_index_extensions=on (インデックス拡張機能を使用)
- condition_fanout_filter=on (条件付き (ファンアウト) フィルタリング)
- derive_merge=on (ビュー/派生テーブルのマージ、Auto_key と連携する必要があります)
今日の内容に戻ると、通常の状況下でクエリを実行する場合、MySQL は最大でも 1 つのセカンダリ インデックスのみを使用すると述べましたが、特殊なケースでは、次のことも可能です。クエリで複数のセカンダリ インデックスを使用します。MySQL では、クエリを完了するために複数のインデックスを使用するこの実行方法をインデックス マージと呼びます。これは、最上位にランクされる最適化機能です。具体的には、インデックス マージ アルゴリズムには次の 3 種類があります。
4.1 交差点の合流
Intersection の直訳は交差点です。これは、特定のクエリで複数のセカンダリ インデックスを使用でき、複数のセカンダリ インデックスからクエリされた結果が交差することを意味します。
mysql> select * from demo8 where key1='4a' AND key3='c84';
このクエリが交差マージを使用して実行される場合、プロセスは次のようになります。
- idx_key1 セカンダリインデックスに対応する B+ ツリーから key1 = '4a' の関連レコードを取り出します。
- idx_key3 セカンダリインデックスに対応する B+ ツリーから key3 = 'c84' の該当レコードを取り出します。
- セカンダリ インデックスのレコードはインデックス列 + 主キーで構成されているため、2 つの結果セットの ID 値の共通部分を計算できます。
- 前のステップで生成された ID 値リストに従ってテーブルに戻ります。つまり、指定された ID 値を持つ完全なユーザー レコードをクラスター化インデックスから取り出してユーザーに返します。
ここにいる学生の中には、idx_key1 または idx_key3 を直接使用して、特定の検索条件に基づいてセカンダリ インデックスを読み取り、テーブルに戻った後に別の検索条件をフィルタリングしてはどうだろうかと考える人もいるでしょう。以下は、2 つのクエリ実行方法間のコストの分析です。
セカンダリ インデックスを 1 つだけ読み取る場合のコストは次のとおりです。
- 特定の検索条件に従ってセカンダリ インデックスを読み取ります。
- セカンダリインデックスから取得した主キー値に従ってテーブルに戻り、他の検索条件をフィルタリングします。
複数のセカンダリ インデックスを読み取った後、交差コストを計算します。
- 異なる検索条件に従って異なるセカンダリインデックスを読み取ります。
- 複数のセカンダリ インデックスから取得した主キー値の共通部分を取得し、テーブルに戻ります。
複数のセカンダリ インデックスの読み取りは 1 つのセカンダリ インデックスの読み取りよりもパフォーマンスを消費しますが、セカンダリ インデックスの読み取り操作はシーケンシャル I/O であるのに対し、テーブルに戻る操作はランダム I/O であるため、セカンダリ インデックスが 1 つだけ読み取られる場合はインデックス作成時にテーブルに返す必要があるレコードの数は非常に多く、複数のセカンダリ インデックスの読み取り後に交差するレコードの数は非常に少ないため、テーブルに返すことによって生じるパフォーマンスの損失が、パフォーマンスに比べて節約される場合複数のセカンダリ インデックスにアクセスすることによってもたらされる損失が大きい場合、1 つのセカンダリ インデックスのみを読み取るよりも、複数のセカンダリ インデックスの共通部分を読み取る方がコストが安くなります。
MySQL は、特定の特定の状況でのみ交差インデックスのマージを使用できます。
状況 1:セカンダリ インデックス列が等価一致である場合、ジョイント インデックスの場合、ジョイント インデックス内の各列が等価一致である必要があり、列の一部のみが一致することはできません。
たとえば、次のクエリでは、2 つのセカンダリ インデックス idx_key1 と idx_key_part を使用して、Intersection インデックスを結合する操作を実行できます。
mysql> select * from demo8 where key1 = 'a' and key_part1 = 'a' and key_part2 = 'b' and key_part3 = 'c';
次の 2 つのクエリは、Intersection インデックスとマージできません。
mysql> select * from demo8 where key1 > 'a' and key_part1 = 'a' and key_part2 = 'b' and key_part3 = 'c';
mysql> select * from demo8 where key1 = 'a' and key_part1 = 'a';
1 つ目のクエリは key1 に対して範囲一致が実行されるため、2 つ目のクエリは結合インデックス idx_key_part の key_part2 列が検索条件に現れないため、これら 2 つのクエリは Intersection インデックスとマージできません。
ケース 2:主キー列が範囲一致である可能性があります。
たとえば、次のクエリでは主キーと idx_key1 を使用して Intersection インデックスをマージできます。
mysql> select * from demo8 where id > 100 and key1 = 'a';
InnoDB のセカンダリ インデックスの場合、レコードはまずインデックス列に従って並べ替えられます。セカンダリ インデックスがジョイント インデックスの場合は、ジョイント インデックスの列に従って並べ替えられます。二次インデックスのユーザー レコードはインデックス列 + 主キーで構成されます。二次インデックス列の値が同じレコードが多数存在する可能性があり、これらのインデックス列の値が同じレコードは、インデックス列の値に従ってソートされます。主キー。交差インデックスのマージは、セカンダリ インデックスの列がすべて同等に一致する場合にのみ可能です。この場合に限り、セカンダリ インデックスに基づいてクエリされた結果セットが主キーの値に従って並べ替えられるためです。
それで?セカンダリ インデックスに基づいてクエリされた結果セットが主キーの値に従って並べ替えられることをまだ理解していません。インターセクション インデックスを使用してマージする利点は何ですか? 交差インデックスのマージは、複数のセカンダリ インデックスからクエリされた主キー値と交差することを忘れないでください。各セカンダリ インデックスからクエリされた結果セットがすでに主キーに従って並べ替えられている場合、交差を見つけるプロセスはとても簡単です。クエリが交差インデックスのマージを使用して、2 つのセカンダリ インデックス idx_key1 と idx_key2 からそれぞれ主キー値を取得すると仮定します。
- idx_key1 からソートされた主キー値を取得します: 1、3、5
- idx_key2 からソートされた主キー値を取得します: 2、3、4
次に、交差を見つけるプロセスは次のようになります。2 つの結果セット内の最小の主キー値を 1 つずつ取り出し、2 つの値が等しい場合は、それを最終的な交差結果に追加します。そうでない場合は、現在の小さい主キー値を破棄します。キー値を取得し、破棄された値を取得します 特定の結果セット内の主キー値が使い果たされるまで、主キー値が配置されている結果セットの最後の主キー値を比較します。それでも理解できない場合は、次の手順に進みます。読む:
- まず、比較のために 2 つの結果セットの小さい方の主キー値を取り出します。1 < 2 であるため、idx_key1 の結果セットの主キー値 1 を破棄し、後者の 3 を比較のために取り出します。
- 3 > 2 であるため、idx_key2 の結果セットの主キー値 2 は破棄され、後者の 3 が比較のために取り出されます。
- 3 = 3 であるため、最終的な交差結果に 3 を追加し、2 つの結果セットの背後にある主キー値の比較を続けます。
- 次の主キー値も等しくないため、最終的な交差結果には主キー値 3 のみが含まれます。
記述した内容の複雑さにも関わらず、実際にはこのプロセスは非常に高速であり、時間計算量は O(n) ですが、各セカンダリ インデックスからクエリされた結果セットが主キーによって並べ替えられていない場合、結果は次のようになります。まず、集中化された主キーの値がソートされた後、上記のプロセスを実行すると時間がかかります。
ヒント:
順序付けされた主キー値に従ってテーブルからレコードを取得するための適切な用語があります。これは、Rowid Ordered Retrieval (略して ROR) と呼ばれます。今後、いくつかの場所でこの用語を目にするときに、この用語に慣れるでしょう。 。
また、複数のセカンダリ インデックス間でインターセクション インデックス マージを使用できるだけでなく、クラスター インデックスもインデックス マージに参加させることができます
。インターセクション インデックス マージインデックス マージを使用します。主キーが範囲一致できるのはなぜですか? さらにアプリケーション シナリオに戻る必要があります。たとえば、次のクエリを見てください。
mysql> select * from demo8 where key1 = 'a' and id > 100;
このクエリが Intersection インデックスを使用してマージできると仮定すると、このクエリは id > 100 の条件に従ってクラスタード インデックスからいくつかのレコードを取得し、次の条件を通じて idx_key1 セカンダリ インデックスからいくつかのレコードを取得することは当然のことと考えます。 key1 = 'a' として、交差部分を見つけます。実際、これは問題を複雑にしており、クラスター化インデックスからレコードを取得する必要はありません。セカンダリ インデックスのレコードにはすべて主キー値があることを忘れないでください。そのため、idx_key1 から取得した主キー値に対して条件 ID > 100 フィルターを直接実行できます。これは非常に簡単です。したがって、主キーの検索条件は、
他の二次インデックスから得られる結果集合からレコードを絞り込むだけであり、等価一致かどうかは重要ではありません。
もちろん、上記のケース 1 とケース 2 は、交差点インデックスのマージが発生するための必要条件にすぎず、十分条件ではありません。ケース 1 とケース 2 が当てはまる場合でも、交差インデックスのマージは必ずしも発生するとは限らず、最終的にはオプティマイザーの選択に依存します。オプティマイザは、検索条件のみに基づいてセカンダリ インデックスから取得したレコードの数が多すぎて、テーブルに返すコストと返す必要があるレコードの数が多すぎる場合にのみ、交差インデックスのマージを使用します。 Intersection インデックスを介したマージ後のテーブルへの変換は大幅に削減されます。
4.2 組合の合併
クエリ文を書くとき、ある検索条件を満たすレコードを取り出し、さらに別の検索条件を満たすレコードも取り出したいことがありますが、これらの異なる検索条件は OR の関係にあると言えます。場合によっては、OR 関係の異なる検索条件で異なるインデックスが使用されることがあります。次に例を示します。
mysql> select * from demo8 where key1 < 'a' or key3 > 'z';
Intersection は交差の意味で、異なるインデックスを使用した検索条件を and で接続した場合に適用され、Union は和集合の意味で、異なるインデックスを使用した検索条件を or で接続した場合に適用されます。Intersection インデックスのマージと同様に、MySQL は特定の状況下でのみ Union インデックスのマージを使用します。
状況 1:セカンダリ インデックス列が等価一致である場合、ジョイント インデックスの場合、ジョイント インデックス内の各列が等価一致である必要があり、一致する列の一部のみが表示されることはできません。
たとえば、次のクエリでは、2 つのセカンダリ インデックス idx_key1 と idx_key_part を使用して、Union インデックスをマージします。
mysql> select * from demo8 where key1 = 'a' or ( key_part1 = 'a' and key_part2 = 'b' and key_part3 = 'c');
ただし、次の 2 つのクエリは Union インデックスとマージできません。
mysql> select * from demo8 where key1 > 'a' or (key_part1 = 'a' and key_part2 = 'b' and key_part3 = 'c');
mysql> select * from demo8 where key1 = 'a' or key_part1 = 'a';
1 つ目のクエリは key1 に対して範囲一致が実行されるため、2 つ目のクエリは結合インデックス idx_key_part の key_part2 列が検索条件に現れないため、これら 2 つのクエリは Union インデックスとマージできません。
ケース 2:主キー列が範囲一致である可能性があります。
ケース 3: Intersection インデックスでマージされた検索条件を使用する (この状況は実際には非常に理解しやすいです。つまり、検索条件の一部で、Intersection インデックスをマージして得られた主キー セットと取得された主キー セットの共通部分が使用されます)他の方法で)。
この状況は実際には非常に理解しやすいものです。つまり、検索条件の一部では、Intersection
インデックスのマージによって取得された主キー セットと、次のクエリなどの他の方法で取得された主キー セットの共通部分が使用されます。
mysql> select * from single_table where key_part1 = 'a' and key_part2 = 'b' and key_part3 = 'c' or (key1 = 'a' and key3 = 'b');
オプティマイザはこのクエリを次の方法で実行します。
- まず、検索条件 key1 = 'a' AND key3 = 'b' に従って、Intersection インデックスを使用してインデックス idx_key1 と idx_key3 をマージすることによって主キー セットが取得されます。
- 次に、検索条件 key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c' に従って、結合インデックス idx_key_part から別の主キー セットを取得します。
- 上記 2 つの主キー セットをユニオン インデックス マージによってマージし、テーブルに戻し、結果をユーザーに返します。
もちろん、クエリ条件がこれらの条件を満たしていれば、必ずしも Union インデックスのマージが採用されるわけではなく、最終的にはオプティマイザの選択に依存します。オプティマイザは、検索条件のみに基づいてセカンダリ インデックスから取得されるレコードの数が比較的少なく、ユニオン インデックス マージによるアクセスのコストが全テーブル スキャンのコストよりも低い場合にのみ、ユニオン インデックス マージを使用します。
4.3 ソートとユニオンのマージ
Union インデックスのマージの使用条件が厳しすぎるため、各セカンダリ インデックスのカラムが等価一致の条件で使用できることを保証する必要があります。たとえば、次のクエリではユニオン インデックスのマージを使用できません。
mysql> select * from demo8 where key1 < 'a' and key3 > 'z';
これは、key1 < 'a' に従って idx_key1 インデックスから取得されたセカンダリ インデックス レコードの主キー値がソートされておらず、key3 に従って idx_key3 インデックスから取得されたセカンダリ インデックス レコードの主キー値がソートされていないためです。 > 'z' キーの値はソートされていませんが、key1 < 'a' と key3 > 'z' の 2 つの条件が特に魅力的であるため、次のようにすることができます。
- まず、key1 < 'a' 条件に従って idx_key1 セカンダリ インデックスからレコードを取得し、レコードの主キー値に従って並べ替えます。
- key3 > 'z' 条件に従って、レコードは常に idx_key3 セカンダリ インデックスから取得され、レコードの主キー値に従って並べ替えられます。
- 上記2つのセカンダリインデックスの主キー値はソートされているため、残りの操作はユニオンインデックスのマージ方法と同じです
まず、セカンダリインデックスに記録されている主キーの値に従って上記をソートし、次にユニオンインデックスマージ方法に従って実行します。これはソート-ユニオンインデックスマージと呼ばれます。単純なユニオン インデックス マージよりも一歩進んだ、セカンダリ インデックス レコードの主キー値を並べ替えるプロセスです。
ヒント:
ソート - ユニオン インデックス マージがあるのに、ソート - 交差インデックス マージがないのはなぜですか? はい、確かに、ソートと交差のインデックスのマージなどはありません。Sort-Union に適用できるシナリオは、検索条件のみに基づいてセカンダリ インデックスから取得されるレコードの数が比較的少ないため、主キー値に従ってこれらのセカンダリ インデックス レコードを並べ替えるコストがそれほど高くないことです。Intersection インデックスのマージに適用されるシナリオは、検索条件のみに基づいてセカンダリ インデックスから取得されるレコードが多すぎるため、テーブルに戻る際のオーバーヘッドが多すぎるというものです。マージ後、テーブルに戻る際のオーバーヘッドが大幅に増加する可能性があります。削減されますが、Sort-Intersection を追加すると、主キーの値に従って多数のセカンダリ インデックス レコードを並べ替える必要があり、このコストはテーブルにクエリを戻すコストよりも高くなる可能性があるため、Sort-Intersection は導入されません。
4.4 ジョイントインデックスのマージに関する注意事項
交差点インデックスのマージではなくジョイントインデックス
mysql> select * from demo8 where key1 = 'a' and key3 = 'b';
Intersection インデックスを組み合わせてこのクエリが実行される理由は、idx_key1 と idx_key3 が 2 つの別個の B+ ツリー インデックスであるためではありません。これら 2 つの列の結合インデックスを作成する場合は、この結合インデックスを直接使用して処理を完了します。なぜわざわざ次のようにインデックスとマージするのでしょうか:
mysql> alter table demo8 drop index idx_key1, idx_key3, add index idx_key1_key3(key1, key3);
このようにして、無駄な idx_key1 と idx_key3 を削除し、結合インデックス idx_key1_key3 を追加します。この結合インデックスを使用してクエリを実行すると、単純に高速で優れています。追加の B+ ツリーを読み取ったり、結果をマージしたりする必要はありません。なぜのためではないですか?
ヒント:
ただし、key3 列が個別にクエリされるビジネス シナリオがあるため、key3 列の個別のインデックスを追加する必要があることに注意してください。
要約する
今日は、MySQL の単一テーブルへのアクセス方法と、最適化機能とインデックスのマージについて学びましたので、以下にまとめます。
-
単一テーブルのアクセス方法:
- const: 主キーまたは一意の副インデックス列を介してレコードを見つけるためのアクセス方法は次のように定義されます: const (一定レベルを意味し、コストは無視できます)。
- ref: 検索条件は、セカンダリ インデックス列の等価値と定数の比較であり、セカンダリ インデックスを使用してクエリを実行するアクセス方法は ref と呼ばれます。
- ref_or_null: フル テーブル スキャンの代わりにセカンダリ インデックスを使用してクエリが実行される場合、このタイプのクエリで使用されるアクセス メソッドは ref_or_null と呼ばれます。
- range: 範囲一致にインデックスを使用するアクセス メソッドは、range と呼ばれます。
- Index: セカンダリ インデックス レコードを走査する実行メソッドは、index と呼ばれます。
- all: フルテーブルスキャンを使用してクエリを実行するメソッドは、all と呼ばれます。
-
インデックスマージのための 3 つのアルゴリズム:
- 交差点のマージ (index_merge_intersection)。
- ユニオンのマージ (index_merge_union)。
- ソートとユニオンのマージ (index_merge_sort_union)。
また、インデックス結合の 3 つのアルゴリズムのトリガー条件には必要な条件と不十分な条件があり、最終的に該当するアルゴリズムが使用されるかどうかはオプティマイザーが判断する必要があることもわかりました。同時に、レンジアクセス方式で使用されるレンジ間隔を学習し、人為的な分析により異なるインデックスを使用して SQL を実行するコストを見積もりました。今日の内容はより原則的なものですが、非常に理解しやすいので、これまでの MySQL B+ ツリー インデックスの知識を組み合わせて、MySQL 設計の繊細さを感じてください。
今日の勉強はこれで終わりです、あなたが壊れない自分になれることを願っています
~~~
先を見据えて点と点を結ぶことはできません。過去を振り返って接続することしかできません。したがって、点と点が何らかの形であなたの将来につながると信じなければなりません。あなたは何かを信頼しなければなりません - 自分の直感、運命、人生、カルマ、何でも。このアプローチは私を決して失望させず、私の人生に大きな変化をもたらしました
私のコンテンツがあなたのお役に立てましたら、どうぞ点赞
、、、創作は簡単ではありません、皆さんのサポートが私が頑張れる原動力です评论
收藏