PHPインタビューの要点| MySQLインデックスの使用戦略と最適化

MySQLの最適化は、主に構造の最適化(スキームの最適化)とクエリの最適化(クエリの最適化)に分けられます

この記事で説明する高性能のインデックス作成戦略は、主に構造最適化のカテゴリに属します。この記事の内容は、上記の理論的根拠に完全に基づいています。実際、インデックスの背後にあるメカニズムを理解すると、高性能戦略を選択することが純粋な推論になり、これらの戦略の背後にある論理を理解できます。

1つは、サンプルデータベースです。

インデックス作成戦略について説明するために、例として少量のデータを含むデータベースが必要です。この記事では、MySQLの公式ドキュメントで提供されているサンプルデータベースの1つであるemployeesを使用します。このデータベースは中程度の複雑さと大量のデータを持っています。次の図は、このデータベースのER図です(公式のMySQLマニュアルから引用)。

ここに写真の説明を挿入

2.左端のプレフィックスの原則と関連する最適化

インデックスを効率的に使用するための最初の条件は、どの種類のクエリがインデックスを使用するかを知ることです。この問題は、B + Treeの「左端のプレフィックスの原則」に関連しています。次の例は、左端のプレフィックスの原則を示しています。

まず、ジョイントインデックスの概念についてお話します。上記では、インデックスは1つの列のみを参照すると想定していましたが、実際、MySQLのインデックスは、特定の順序で複数の列を参照できます。この種のインデックスは、ジョイントインデックスと呼ばれます。

一般に、結合インデックスは順序付けられたタプル<a1、a2、…、a>であり、各要素はデータテーブルの列です。実際、インデックスを厳密に定義するには、リレーショナル代数を使用する必要がありますが、ここではあまり説明しません。多関係代数のトピックは非常に退屈なので、ここでは厳密な定義はありません。さらに、単一列のインデックスは、ジョイントインデックスの要素数が1である特殊なケースと見なすことができます。

例としてemployees.titlesテーブルを取り上げ、最初にどのインデックスがそのテーブルにあるかを確認しましょう。

ここに写真の説明を挿入

三、説明

日常業務では、遅いクエリを開いて、長時間実行されたSQLステートメントを記録することがあります。これらのSQLステートメントを見つけても、完了したとは限りません。explainコマンドを使用してこれらのSQLステートメントの1つを表示することがよくあります。 SQLステートメントの実行計画では、SQLステートメントがインデックスを使用しているかどうか、テーブル全体のスキャンを実行するかどうかを確認します。これは、explainコマンドで確認できます。

そのため、MySQLのコストベースのオプティマイザについて深く理解しています。また、オプティマイザが検討する可能性のあるアクセス戦略や、SQLステートメントの実行時にオプティマイザが採用することが期待される戦略について多くの詳細を取得できます。

EXPLAINからの情報には、id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extraの10列があります。

要約の説明:

  • id:識別子を選択
  • select_type:クエリのタイプを示します。
  • table:出力結果セットのテーブル
  • type:テーブルの接続タイプを示します

all(フルテーブルスキャン)、index(インデックスの順序に従ったフルテーブルスキャン)、range(範囲インデックススキャン)
req(検索条件列はインデックスを使用し、プライマリキーではなく一意であり、インデックス列の値は一意ではありません)、ref_eq(プライマリキーまたは一意のインデックスが検索に使用される場合)、
const(プライマリキーは、条件付きクエリとして、mysqlオプティマイザがこのクエリを定数に最適化できる場所の後に配置されます)

  • possible_keys:クエリ時に使用できるインデックスを示します
  • キー:実際に使用されているインデックスを示します
  • key_len:インデックスフィールドの長さ
  • 参照:列とインデックスの比較
  • 行:スキャンされた行数(推定行数)
  • 追加:実装の説明と説明

4つの特定のコンテンツ

ケース1:完全な列の一致

ここに写真の説明を挿入

explain SELECT * FROM employees.titles WHERE emp_no='10001' AND title = 'Senior Engineer' AND from_date='1986-06-26';

明らかに、インデックスは、インデックス内のすべての列に従って完全一致を実行するときに使用できます(ここで、完全一致は「=」または「IN」一致を指します)。ここで注意すべきことの1つは、インデックスは理論的に順序に敏感ですが、MySQLのクエリオプティマイザは適切なインデックスを使用するためにwhere句の条件付き順序を自動的に調整するため、たとえば、効果が同じである条件の順序を逆にします。 。

ケース2:左端のプレフィックスが一致する

ここに写真の説明を挿入

EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001';

クエリ条件が、または<emp_no、title>など、インデックスの左側にある1つまたは複数の列と完全に一致する場合、使用できますが、その一部、つまり条件で構成される左端のプレフィックスのみが使用できます。上記のクエリは分析結果のPRIMARYインデックスを使用しますが、key_lenは4であり、インデックスの最初の列プレフィックスのみが使用されていることを示しています。

ケース3:クエリ条件はインデックスの列の完全一致を使用しますが、中央の条件の1つが提供されていません

ここに写真の説明を挿入

EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001' AND from_date='1986-0626';

現時点では、タイトルが指定されていないため、インデックスの使用法はケース2と同じです。したがって、クエリはインデックスの最初の列のみを使用し、後のfrom_dateもインデックスに含まれますが、タイトルが存在しないため、左側のプレフィックスと接続できないため、必要です。 from_dateの結果をスキャンしてフィルタリングします(ここでは、emp_noは一意であるため、スキャンはありません)。

from_dateでフィルタリングする場所の代わりにインデックスも使用する場合は、補助インデックス<emp_no、from_date>を追加すると、上記のクエリでこのインデックスが使用されます。さらに、「分離列」と呼ばれる最適化方法を使用して、emp_noとfrom_dateの間の「ピット」を埋めることもできます。

まず、タイトルを見てみましょう。いくつかの異なる値があります。

MySQLインデックスの使用戦略と最適化

7種類しかありません。「ピット」と呼ばれる列の値が少ないこの場合、「IN」を使用して「ピット」を埋め、左端のプレフィックスを形成することを検討できます。

ここに写真の説明を挿入

今回のkey_lenは56で、インデックスが使い果たされていることを示していますが、タイプと行から、INが実際に範囲クエリを実行したことがわかります。ここでは7つのキーがチェックされています。

「穴を埋める」と少し性能が向上しました。emp_noフィルタリングの後に大量のデータが残っている場合、後者のパフォーマンス上の利点はより明白になります。もちろん、タイトルの値が多すぎる場合、穴を埋めるのは適切ではなく、補助インデックスを確立する必要があります。

状況4:クエリ条件でインデックスの最初の列が指定されていない

ここに写真の説明を挿入

左端のプレフィックスではないため、インデックスは明らかにインデックスなどのクエリには使用されません。

状況5:列のプレフィックス文字列と一致する

ここに写真の説明を挿入

この時点でインデックスを使用できますが、ワイルドカードが最後に表示されているだけではない場合、インデックスは使用できません。(元のテキストが正しくありません。ワイルドカード%が最初に表示されない場合は、インデックスを使用できますが、特定の状況によっては、プレフィックスの1つのみを使用できます)

状況6:範囲クエリ

ここに写真の説明を挿入

範囲列はインデックスを使用できますが(左端のプレフィックスである必要があります)、範囲列の後の列はインデックスを使用できません。同時に、インデックスは最大で1つの範囲列に使用されるため、クエリ条件に2つの範囲列がある場合、インデックスをすべて使用することはできません。

ここに写真の説明を挿入

インデックスは2番目の範囲インデックスでは何もできないことがわかります。これは、MySQLが興味深いことを説明するための特別なポイントです。つまり、explainを使用するだけでは、範囲インデックスと複数値の一致を区別できない場合があります。どちらもタイプの範囲として表示されるためです。同時に、「between」を使用しても、次のクエリなどの範囲クエリであるとは限りません。

ここに写真の説明を挿入

2つの範囲クエリが使用されているようですが、emp_noに作用する「BETWEEN」は実際には「IN」と同等です。つまり、emp_noは実際には複数値の完全一致です。このクエリはインデックスの3つの列すべてを使用していることがわかります。したがって、MySQLでは複数値マッチングと範囲マッチングを慎重に区別する必要があります。そうしないと、MySQLの動作が混乱します。

ケース7、インデックスの選択とプレフィックスインデックス

インデックスはクエリを高速化できるので、クエリステートメントで必要な限りインデックスを作成する必要がありますか?答えは否定的です。インデックスはクエリを高速化しますが、インデックスには代償があります。インデックスファイル自体がストレージスペースを消費し、インデックスはレコードの挿入、削除、変更の負担を増やします。さらに、MySQLは、実行時にインデックスを維持するためのリソースも消費します。したがって、インデックスは良くありません。一般に、2つのケースでインデックスを作成することはお勧めしません。

最初のケースは、テーブルレコードが比較的小さい場合です。たとえば、1〜2000レコード、さらには数百レコードのテーブルです。インデックスを作成する必要はありません。クエリでテーブル全体をスキャンするだけです。数えられるレコードの数については、個人的な意見があります。私の個人的な経験では、2000を分割線としています。レコード数が2000を超えない場合はインデックスを作成しないことを検討でき、2000を超える場合は適切にインデックスを作成することを検討できます。

インデックス作成が推奨されないもう1つの状況は、インデックスの選択性が低いことです。いわゆるインデックス選択性(選択性)は、テーブルレコードの数(#T)に対する一意のインデックス値(カーディナリティとも呼ばれます)の比率を指します。

Index Selectivity = Cardinality / #T

明らかに、選択範囲は(0、1]であり、選択性が高いほど、B + Treeの性質によって決定されるインデックスの値が大きくなります。たとえば、タイトルフィールドが上記のemployees.titlesテーブルの場合インデックスを作成する必要があるかどうかは、個別に照会されることがよくあります。その選択性を見てみましょう。

ここに写真の説明を挿入

タイトルの選択性は0.0001未満(正確な値は0.00000179)であるため、別のインデックスを作成する必要はありません。

インデックスキーとして列全体ではなく列のプレフィックスを使用するプレフィックスインデックスと呼ばれるインデックス選択性に関連するインデックス最適化戦略があります。プレフィックス長が適切な場合、プレフィックスインデックスの選択性は完全な列インデックスの選択性に近くなります。インデックスキーが短くなり、インデックスファイルのサイズとメンテナンスのオーバーヘッドが削減されます。以下では、プレフィックスインデックスの選択と使用を紹介する例としてemployees.employeesテーブルを取り上げます。

サンプルのデータベース図から、employeesテーブルにはインデックスが1つしかないことがわかります。名前で人を検索する場合は、テーブル全体しかスキャンできません。名前で従業員を頻繁に検索する場合、これは明らかに非常に非効率的であるため、インデックスの作成を検討できます。 。buildまたは<first_name、last_name>の2つのオプションがあり、2つのインデックスの選択性を確認します。

ここに写真の説明を挿入

明らかに選択性が低すぎて、選択性は非常に良いですが、first_nameとlast_nameの全長は30ですが、長さと選択性のバランスをとる方法はありますか?>> first_nameとlast_nameの最初の数文字を使用してインデックスを作成することを検討してください。たとえば、その選択性を確認します。

MySQLインデックスの使用戦略と最適化

現時点では、選択性が理想的であり、このインデックスの長さはわずか18であり、それよりもほぼ半分短いです。このプレフィックスインデックスを作成します。ALTER TABLE employees.employees ADD INDEX `first_name_last_name4 `(first_name, last_name (4));この時点で、名前でクエリを再度実行し、インデックスの前に結果を比較して分析します。パフォーマンスが大幅に向上し、クエリ速度が120倍以上向上しました。

プレフィックスインデックスは、インデックスサイズとクエリ速度を考慮しますが、その欠点は、ORDERBYおよびGROUPBY操作に使用できず、インデックスをカバーするためにも使用できないことです(つまり、インデックス自体にクエリに必要なすべてのデータが含まれている場合、データファイル自体にアクセスできなくなります)。

注意してください、迷子にならないでください

さて、みなさん、上記はこの記事の全内容です。ここで見ることができるのはすべて才能です。さっきも言ったように、PHPには技術的なポイントがたくさんあります。多すぎるので、書くのは本当に不可能で、書いた後はあまり読まないので、必要に応じてここでPDFとドキュメントに整理します。できる

クリックしてシークレットコードを入力してください:PHP +「プラットフォーム」

ここに写真の説明を挿入

ここに写真の説明を挿入


学習内容の詳細については、[Comparative Standard Factory]の優れたPHPアーキテクトチュートリアルカタログをご覧ください。給与が確実に上がるように読むことができます(継続的な更新)

上記のコンテンツは、すべての人に役立つことを願っています。多くのPHP担当者は、上級者になると常に問題やボトルネックに直面します。ビジネスコードを書きすぎると、方向性がわかりません。どこから改善を始めればよいかわかりません。これに関する情報をまとめました。ただし、これらに限定されません。分散アーキテクチャ、高スケーラビリティ、高パフォーマンス、高同時実行性、サーバーパフォーマンスチューニング、TP6、laravel、YII2、Redis、Swoole、Swoft、Kafka、Mysql最適化、シェルスクリプト、Docker、マイクロサービス、Nginxなど。多くの知識ポイント、高度な高度な乾物は、誰とでも無料で共有でき、必要な人は私のPHPテクノロジー交換グループに参加できます

おすすめ

転載: blog.csdn.net/weixin_49163826/article/details/108760331