1つ、説明
MySQLの最適化を行うには、EXPLAINをうまく利用し てSQL実行計画を表示する必要があり ます。
これは簡単な例で、焦点を合わせたいデータにラベルを付けます(1,2,3,4,5)
- タイプ列、接続タイプ。優れたSQLステートメントは、少なくとも範囲レベルに到達する必要があります。すべてのレベルに終止符を打つ
- キー列、使用されるインデックス名。インデックスが選択されていない場合、値はNULLです。必須の索引付けを採用できます
- key_len列、インデックスの長さ
- 行列、スキャン行の数。この値は推定値です
- 追加の列、詳細な説明。一般的な不親切な値は次のとおりです:ファイルソートの使用、一時的な使用
2つ目は、SQLステートメントのINの値が多すぎないことです。
MySQLは、INに対応する最適化を行いました。つまり、INのすべての定数が配列に格納され、この配列がソートされます。ただし、値が大きい場合、消費量は比較的多くなります。別の例:select id from table_name where num in(1,2,3)
連続値の場合、間で使用できる場合はで使用しないでください。または、接続を使用して置き換えてください。
3つ目は、SELECTステートメントでフィールド名を指定する必要があることです。
SELECT *は、多くの不要な消費(cpu、io、メモリ、ネットワーク帯域幅)を増やします。カバーするインデックスを使用する可能性を高めます。テーブル構造が変更された場合、プリブレークも更新する必要があります。そのため、選択の直後にフィールド名を接続する必要があります。
4.必要なデータが1つだけの場合は、制限1を使用します。
これは、EXPLAINのtype列をconsttypeに到達させるためです。
5.インデックスが並べ替えフィールドで使用されていない場合は、並べ替えをできるだけ少なくしてください
6.制限条件の他のフィールドにインデックスがない場合は、使用するか、できるだけ少なくします。
またはの両側のフィールドの1つがインデックスフィールドではなく、他の条件がインデックスフィールドでない場合、クエリはインデックス付けされません。多くの場合、より良い結果を得るために、「または」の代わりにunion allまたはunion(必要な場合)を使用します
セブン、ユニオンの代わりにすべてユニオンを使用してみてください
unionとunionallの主な違いは、前者は結果セットを組み合わせてから、並べ替え、多くのCPU操作の増加、リソース消費の増加、および遅延を伴う独自のフィルタリング操作を実行する必要があることです。もちろん、すべてを結合するための前提条件は、2つの結果セットに重複データがないことです。
8. ORDER BY RAND()を使用しないでください
select id from `table_name` order by rand() limit 1000;
上記のsqlステートメントは次のように最適化できます
select id from `table_name` t1 join (select rand() * (select max(id) from `table_name`) as nid) t2 ont1.id > t2.nid limit 1000;
9、存在するものと存在しないもの、存在しないものと存在しないものを区別する
select * from 表A where id in (select id from 表B)
上記のsqlステートメントは同等です
select * from 表A where exists(select * from 表B where 表B.id=表A.id)
inとexistsを区別する主な理由は、駆動順序の変更です(これがパフォーマンス変更の鍵です)。存在する場合は、外側のテーブルが駆動テーブルであり、最初にアクセスされます。INの場合は、サブクエリが最初に実行されます。したがって、INは外面が大きく内面が小さい場合に適しており、EXISTSは外面が小さく内面が大きい場合に適しています。
存在しない、存在しないということに関しては、効率だけでなく、存在しないを使用することをお勧めします。存在しないものを置き換えるSQLステートメントを効率的に作成するにはどうすればよいですか?
元のsqlステートメント
select colname … from A表 where a.id not in (select b.id from B表)
効率的なsqlステートメント
select colname … from A表 Left join B表 on where a.id = b.id where b.id is null
取得した結果セットを次の図に示します。テーブルAのデータはテーブルBにはありません。
10.適切なページング方法を使用して、ページングの効率を向上させます
select id,name from table_name limit 866613, 20
上記のsqlステートメントをページングに使用すると、テーブルデータの量が増えると、制限ページングクエリを直接使用するとますます遅くなることがあります。
最適化の方法は次のとおりです。前のページの最大行数のIDを取得し、この最大IDに従って次のページの開始点を制限できます。たとえば、この列では、前のページの最大IDは866612です。sqlは次のように書くことができます。
select id,name from table_name where id> 866612 limit 20
11.セグメントクエリ
一部のユーザー選択ページでは、一部のユーザーが長すぎる時間範囲を選択し、クエリが遅くなる場合があります。主な理由は、スキャンラインが多すぎることです。このとき、プログラムを使用して、セグメントごとにクエリを実行し、ループして、結果をマージして表示することができます。
次の図に示すように、スキャンされた行が数百万レベルを超える場合、このsqlステートメントはセグメント化されたクエリを使用できます。
12.where句のフィールドのnull値の判断を避けます
nullと判断されると、エンジンはインデックスの使用をあきらめ、テーブル全体のスキャンを実行します。
13.%プレフィックスファジークエリの使用はお勧めしません
たとえば、LIKE "%name"またはLIKE "%name%"の場合、この種のクエリはインデックスに失敗し、テーブル全体のスキャンを実行します。ただし、LIKE "name%"を使用できます。
%name%を照会する方法は?
下の図に示すように、シークレットフィールドにインデックスが追加されますが、explainの結果は使用されません。
したがって、この問題を解決する方法、答え:フルテキストインデックスを使用する
クエリでは、user_nameが '%zhangsan%';のように、table_nameからselect id、fnum、fdstを使用することがよくあります。このようなステートメントの場合、通常のインデックスはクエリ要件を満たすことができません。幸い、MySQLには、役立つフルテキストインデックスがあります。
フルテキストインデックスを作成するためのsql構文は次のとおりです。
ALTER TABLE `table_name` ADD FULLTEXT INDEX `idx_user_name` (`user_name`);
フルテキストインデックスを使用するsqlステートメントは次のとおりです。
select id,fnum,fdst from table_name where match(user_name) against('zhangsan' in boolean mode);
注:フルテキストインデックスを作成する必要がある前に、DBAに連絡して、作成できるかどうかを確認してください。同時に、クエリステートメントと通常のインデックスの違いに注意する必要があります
14.where句のフィールドでの式操作は避けてください
といった
select user_id,user_project from table_name where age*2=36;
フィールドに対して算術演算が実行されるため、エンジンはインデックスの使用を中止します。次のように変更することをお勧めします。
select user_id,user_project from table_name where age=36/2;
15.暗黙的な型変換を避けます
where句の列フィールドのタイプが渡されたパラメータのタイプと矛盾する場合に発生するタイプ変換。whereでパラメータのタイプを判別することをお勧めします。
[画像のアップロードに失敗しました...(image-bd63df-1553758116677)]
16.ジョイントインデックスの場合、左端のプレフィックスルールを遵守する必要があります
たとえば、インデックスにはフィールドid、name、schoolが含まれ、idフィールドを直接使用することも、id、name、nameの順序を使用することもできます。学校はこのインデックスを使用できません。したがって、ジョイントインデックスを作成するときは、インデックスフィールドの順序に注意する必要があります。一般的に使用されるクエリフィールドは上部に配置されます。
17.必要に応じて、force indexを使用して、クエリを強制的にインデックスに移動させることができます。
有的时候MySQL优化器采取它认为合适的索引来检索sql语句,但是可能它所采用的索引并不是我们想要的。这时就可以采用force index来强制优化器使用我们制定的索引。
18.範囲クエリステートメントに注意してください
ジョイントインデックスの場合、間、>、<などの範囲クエリがあると、後続のインデックスフィールドは無効になります。
19.JOIN最適化について
- LEFTJOINテーブルはドライビングテーブルです
- 内部結合MySQLは、テーブルを駆動するためのデータが少ないテーブルを自動的に検索します
- RIGHT JOINBテーブルはドライビングテーブルです
注:MySQLには完全な結合はありません。次の方法を使用して、解決できます。
select * from A left join B on B.name = A.name
where B.name is null
union all
select * from B;
内部結合を使用して、左結合を避けてください
共同クエリに参加しているテーブルは少なくとも2つあり、通常はサイズに違いがあります。接続方法が内部結合の場合、MySQLは他のフィルター条件なしで駆動テーブルとして小さなテーブルを自動的に選択しますが、左結合は駆動テーブルの選択で左駆動の原則に従います。つまり、左結合の左側のテーブル名です。ドライビングテーブル用。
インデックスの合理的な使用
ドリブンテーブルのインデックスフィールドは、onの制限付きフィールドとして使用されます。
小さなテーブルを使用して大きなテーブルを駆動する
概略図から、ドライブテーブルを減らすことができれば、ネストされたループ内のループの数を減らして、IOの合計量とCPU操作の数を減らすことができることが直感的にわかります。
STRAIGHT_JOINの巧妙な使用
内部結合はmysqlによって駆動テーブルを選択しますが、特別な場合には、グループ化、順序付けなど、駆動テーブルとして別のテーブルを選択する必要があります。「ファイルソートの使用」および「一時的な使用」。STRAIGHT_JOINは、接続順序を強制するために使用されます。STRAIGHT_JOINの左側のテーブル名は駆動テーブルであり、右側は駆動テーブルです。STRAIGHT_JOINを使用するための前提条件は、クエリが内部結合であるということです。これは内部結合です。STRAIGHT_JOINは、他のリンクにはお勧めしません。そうしないと、クエリ結果が不正確になる可能性があります。
この方法では、時間が3分の1になる場合があります。
上記の最適化スキームのみがここにリストされています。もちろん、他の最適化方法もあります。探索して試すことができます。ご清聴ありがとうございました。