9. 文字列にインデックスを追加する方法
9.1 プレフィックスインデックス
MySQL はプレフィックス インデックスをサポートしています。デフォルトでは、プレフィックスの長さを指定せずにインデックスを作成すると、インデックスには文字列全体が含まれます。
mysql> alter table teacher add index index1(email);
#或
mysql> alter table teacher add index index2(email(6));
Index1 (つまり、電子メール文字列全体のインデックス構造) を使用している場合、実行シーケンスは次のとおりです。
- Index1 インデックス ツリーからインデックス値が「[email protected]」であるレコードを検索し、ID2 の値を取得します。
- 主キーに移動し、主キー値が ID2 である行を見つけ、電子メールの値が正しいと判断し、この行のレコードを結果セットに追加します。
- Index1 インデックス ツリー内で見つかった位置にある次のレコードを取得し、email='[email protected]' の条件が満たされなくなったことがわかり、ループが終了します。
このプロセス中、主キー インデックスからデータを取得する必要があるのは 1 回だけであるため、システムは 1 行だけがスキャンされたと認識します。
Index2 (つまり、email(6) インデックス構造) を使用している場合、実行シーケンスは次のとおりです。
- Index2 インデックス ツリーからインデックス値 'zhangs' を満たすレコードを検索します。最初に見つかったレコードは ID1 です。
- 主キーに移動し、主キー値が ID1 である行を検索すると、電子メールの値が「 [email protected] 」ではないと判断され、この行のレコードは破棄されます。
- インデックス 2 で見つかった位置にある次のレコードを取得すると、まだ 'zhangs' であることがわかります。ID2 を取り出して、ID インデックスの行全体を取得し、今度は値が正しいと判断します。このレコードの行を次のレコードに追加します。結果セット。
- idxe2 で取得した値が「zhangs」でなくなるまで前のステップを繰り返し、ループが終了します。
つまり、プレフィックス インデックスを使用して長さを定義すると、クエリ コストをあまり追加せずにスペースを節約できます。差別については以前にもお話しましたが、差別は高ければ高いほど良いのです。区別が高くなるほど、重複するキー値が少なくなるからです。
9.2 カバリングインデックスに対するプレフィックスインデックスの影響
結論:
プレフィックス インデックスを使用すると、クエリのパフォーマンスを最適化するためにインデックスをカバーする必要がなくなります。これは、プレフィックス インデックスを使用するかどうかを選択するときに考慮する必要がある要素でもあります。
10. インデックスのプッシュダウン
Index Condition Pushdown (ICP) は MySQL 5.6 の新機能で、インデックスを使用してストレージ エンジン層でデータをフィルタリングする最適化方法です。ICP を使用すると、ストレージ エンジンがベース テーブルにアクセスする回数と、MySQL サーバーがストレージ エンジンにアクセスする回数を減らすことができます。
10.1 使用前後のスキャンプロセス
ICP インデックス スキャンを使用しない場合:
ストレージ層: インデックスキーの条件を満たすインデックスレコードに対応するレコードの行全体のみが取り出され、サーバー層に返されます。
サーバー層: 後続の where 条件を使用して、最後の行が返されるまで返されたデータをフィルター処理します。
ICP スキャンを使用するプロセス:
- ストレージ層:
まず、インデックスキーの条件を満たすインデックスのレコード間隔を決定し、フィルタリングするインデックスに対してインデックスフィルターを使用します。インデックスフィルター条件を満たすインデックスレコードのみがテーブルに返され、レコードの行全体がサーバー層に返されます。インデックス フィルター条件を満たさないインデックス レコードは破棄され、テーブル層やサーバー層には返されません。
- サーバー層:
返されたデータについては、最終的なフィルター処理にテーブル フィルター条件を使用します。
使用前と使用後のコストの違い。使用前は
、ストレージ レイヤーはインデックス フィルターで除外する必要がある多くの行のレコードを返しました。ICP の
使用後は、インデックス フィルターの条件を満たさないレコードが直接削除されるため、インデックス フィルターの必要性がなくなりました。それらはテーブルに返され、サーバー層に渡されます。
ICP の高速化効果は、ストレージ エンジン内で ICP によってフィルタリングされたデータの割合によって異なります。
10.2 ICPの使用条件
ICPの使用条件:
①セカンダリインデックス(セカンダリインデックス)のみ使用可能
②explainで表示される実行プランのtype値(結合タイプ)がrange、ref、eq_ref、ref_or_nullのいずれかになります。
③ ICP ですべての where 条件をフィルタリングできるわけではないため、where 条件のフィールドがインデックス列にない場合でも、where フィルタリングのためにテーブル全体のレコードをサーバーに読み込む必要があります。
④ICPはMyISAMおよびInnnoDBストレージエンジンに使用可能
⑤ MySQL バージョン 5.6 はパーティションテーブルの ICP 機能をサポートしていませんが、バージョン 5.7 からサポートを開始します。
⑥ SQL がカバリングインデックスを使用する場合、ICP 最適化手法はサポートされません。
11. 通常のインデックスと一意のインデックス
パフォーマンスの観点から、一意のインデックスと通常のインデックスのどちらを選択する必要がありますか? 選択の基準は何ですか?
ID として主キー列を持つテーブルがあるとします。テーブルにはフィールド k があり、k にはインデックスがあります。フィールド k の値は繰り返されないとします。このテーブルのテーブル作成ステートメントは次のとおりです。
mysql> create table test(
id int primary key,
k int not null,
name varchar(16),
index (k)
)engine=InnoDB;
表中のR1~R5の(ID,k)値は、それぞれ(100,1)、(200,2)、(300,3)、(500,5)、(600,6)となります。
11.1 クエリプロセス
クエリを実行するステートメントが であると仮定します select id from test where k=5
。
- 通常のインデックスの場合、条件を満たす最初のレコード (5,500) を見つけた後、k=5 条件を満たさない最初のレコードが見つかるまで次のレコードを見つける必要があります。
- 一意のインデックスの場合、インデックスが一意性を定義するため、条件を満たす最初のレコードが見つかった後に検索が停止します。
- では、この違いによって生じるパフォーマンスの違いは何でしょうか? 答えは、最小限です。
11.2 アップデートプロセス
通常のインデックスと一意のインデックスが更新ステートメントのパフォーマンスに与える影響を説明するために、変更バッファを紹介します。
データ ページを更新する必要がある場合、データ ページがメモリ内にあれば直接更新されます。データ ページがまだメモリ内にない場合、InooDB はデータの一貫性に影響を与えることなく、これらの更新操作を変更バッファにキャッシュします
。
このデータ ページをディスクから読み取る必要はありません。次のクエリでこのデータ ページにアクセスする必要がある場合、データ ページをメモリに読み取り、
変更バッファ内のこのページに関連する操作を実行します。このようにして、データロジックの正確性を保証できます。
変更バッファ内の操作を元のデータ ページに適用し、最新の結果を取得するプロセスはマージと呼ばれます。このデータ ページにアクセスするときにマージをトリガーすることに加えて
、システムには定期的にマージするバックグラウンド スレッドがあります。データベースの通常のシャットダウン中に、マージ
操作も実行されます。
更新操作を最初に変更バッファーに記録してディスク読み取りを減らすことができれば、ステートメントの実行速度が大幅に向上します。さらに、
データをメモリに読み込むにはバッファ プールを占有する必要があるため、この方法ではメモリの占有を回避し、メモリ使用率を向上させることもできます。
変更バッファを使用して一意のインデックスを更新することはできず、実際には通常のインデックスのみが使用できます。
12. その他のクエリ最適化戦略
12.1 EXISTS と IN の違い
どの場合に EXISTS を使用する必要があり、どの場合に IN を使用する必要があるのかがよくわかりません。選択基準はテーブルのインデックスが使用できるかどうかでしょうか?
12.2 COUNT(*) および COUNT (特定のフィールド) の効率
質問: MySQL でデータ テーブルの行数をカウントするには、SELECT COUNT(*)、SELECT COUNT(1)、および SELECT
COUNT (特定のフィールド) の 3 つの方法がありますが、これら 3 つの方法間のクエリ効率はどのくらいですか?
12.3 SELECT(*)について
テーブル クエリでは、フィールドを指定することをお勧めします。クエリのフィールド リストとして * を使用しないでください。SELECT <フィールド リスト> クエリを使用することをお勧めします。理由:
① MySQL は解析プロセス中に、データ ディクショナリにクエリを実行することによって、「*」をすべてのカラム名に順番に変換します。これにより、リソースと時間が大幅に消費されます
。
②カバリングインデックスは使用できません
12.4 最適化に対する LIMIT 1 の影響
テーブル全体をスキャンする SQL ステートメントを対象としています。結果セットが 1 つだけであることが確実な場合、LIMIT 1 を追加すると、結果が見つかったときにスキャンが続行されなくなり、クエリが高速化されます。
データ テーブルでフィールドに対して一意のインデックスが確立されている場合は、そのインデックスを介してクエリを実行できます。テーブル全体がスキャンされない場合は、 LIMIT 1を追加する必要はありません。
12.5 COMMIT をさらに使用する
可能な限り、プログラム内で COMMIT をできるだけ使用してください。これにより、プログラムのパフォーマンスが向上し、 COMMIT によって解放される
リソースによって需要が軽減されます。
COMMIT によってリリースされたリソース:
- データのリカバリに使用されるロールバックセグメントに関する情報
- プログラムステートメントによって取得されたロック
- REDO/UNDOログバッファのスペース
- 上記 3 つのリソースに対する内部支出を管理します