SQLを最適化する
最初の一歩
重いSQLステートメントの実行頻度を理解するためのshowstatusコマンドを使用する
第二段階
実行効率の低いSQLステートメントを見つける
方法1:遅いクエリログを使用して、実行効率の低いSQLステートメントを見つけます。slow-query-logパラメーターがONに設定された後、MySQLは実行時間がしきい値を超えるすべてのSQLをslow_quert_log_fileパラメーターで指定されたファイルに書き込みます。
方法2:方法1は、実行後にのみログファイルに書き込まれます。show processListコマンドを使用して、現在実行中のスレッドを表示できます。また、SQLの実行をリアルタイムで表示できます。
3番目のステップ
SQLの分析
方法1:Explainコマンドを使用して非効率的なSQLの実行プランを分析する
方法2:クエリIDにshow profileを使用して(idはshow profileから取得できます)、SQLステートメントの特定の実行中にさまざまなプロセスに必要な時間を表示します。
方法3:オプティマイザーがトレースを通じて実行プランを選択する方法を分析する
SQLの最適化の原則
1.小さなテーブルが大きなテーブルを駆動します
2.インデックスの順序を使用して並べ替えます
3。
Select * from A where A.id in (select B.id from B)#B表驱动A表,相当于先从B表中查出id,然后再在A表中循环匹配(最好B是小表 (驱动表))
Select * from A where exists(select 1 from B where A.id = B.id)# A表驱动B表,相当于先从A表中查找数据,然后再利用B表过滤数据(最好A是小表 (驱动表))
遅いクエリログ
遅いクエリログは、SQL実行時間がしきい値を超えたレコードを記録できます。デフォルトでは、遅いクエリログは閉じられており、手動で開く必要があります。ただし、必要なときにのみオンにし、不要なときにオンにしないでください。開封後は性能に一定の影響を与えるためです。
set global slow_query_log = on
このステートメントを使用して、低速クエリログをオンにすることができます。ただし、これは現時点で現在のデータベースの低速クエリログを開くためだけのものです。再起動後、サーバーに障害が発生します。
永続的に有効にする場合は、mysql構成ファイルに移動して構成する必要があります
SQLが遅いと見なされる秒数を確認します
show VARIABLES like '%long_query_time%' # 查看慢查询日志记录的阈值
つまり、10秒より大きいSQLは遅いSQLです。
set global long_query_time = 1 #设置阈值为1秒
select sleep(2)
注:しきい値は、mysqlに再接続する必要がある場合にのみ変更されます。
mysqldumpslow
mysqldumpslowは、mysqlが提供するツールであり、低速のクエリログファイルをより適切に分析するのに役立ちます。
インデックス
インデックス:ソートされた高速検索データ構造
インデックスタイプ
InnoDB sub ah MySQL5.7は適応ハッシュインデックスをサポートします。いわゆるアダプティブとは、Mysqlがデータアクセスの頻度とモードに応じて一部のホットページのハッシュインデックスを自動的に作成することです。インデックスはバッファプールのB_treeによって自動的に生成され、非常に効率的です。ハッシュインデックスは、Key-Valueクエリに適しています。範囲クエリを使用する場合、ハッシュインデックスは機能しません。
MysQLはインデックスをどのように使用しますか
Bツリーインデックスの最も一般的なインデックスは、バイナリツリーと同様に構築されますが、バイナリツリーではありません。BツリーのBは、二分木の意味ではなく、バランスの意味です。Bツリーインデックスは、完全なキーワード、キーワード範囲、およびキーワードプレフィックスのクエリに使用できます。
Bツリーの構造
ルートノードルートの下に複数のブランチ(ブランチノード)があります。ブランチノードの下には、詳細なリーフ(リーフノード)があります。
インデックスを作成するタイミング
1.主キーは自動的に一意のインデックスを作成します
2.クエリ条件として頻繁に使用されるフィールド
3.クエリ内の他のテーブルに関連付けられたフィールドと外部キーの関係にインデックスが付けられます
4.
クエリで並べ替えられたフィールド5。クエリでカウントまたはグループ化されるフィールド
インデックスを作成しない場合
1.where条件で使用されないフィールド
2.頻繁に更新されるフィールド
3。
インデックスの失敗を防ぐ
左端のマッチング原則
複合インデックスを使用する場合、インデックスの順序が重要です。インデックスを使用する順序は、インデックスを作成する順序と同じである必要があり(myslqのオプティマイザーが正の順序に最適化するため、順序を変えて書き込むことができます)、インデックスの間にインデックスが不足していてはなりません。 。そうしないと、複合インデックスを完全に使用できません。まず第一に、最初のインデックスは失われません。後者のインデックスが壊れている場合、後者のインデックスは機能しませんが、前のインデックスは引き続き有効です。(これは、インデックスデータ構造Bツリーに関連しています)
インデックスを操作しないでください
インデックスを使用できなくなるため、インデックスを操作しないでください。left(index column、n)関数を使用すると、それは不正確なクエリになり、不正確なクエリはインデックス列を無効にします。
範囲の右側にあるすべてのインデックスが無効です
この順序は作成の順序を指します。これは、sqlステートメントの順序がオプティマイザーによって最適な順序に最適化されるためです(mysql 8はこのようなものです)。
explain select * from test19 where id3 = 1 and id2 > 2 and id1 = 1
explain select * from test19 where id2 = 1 and id3 > 2 and id1 = 1
私が作成したインデックスは、(id1 id2 id3)の順序の複合インデックスです。範囲クエリにid2を使用すると、id3のインデックスが無効になります。
カバーインデックスを使用してみてください
入力はselectを使用しません*インデックスにないフィールドを取得する場合は、テーブルに戻ります。
explain select * from test19 where id3 = 1 and id2 > 2 and id1 = 1
explain select id1,id2,id3 from test19 where id3 = 1 and id2 > 2 and id1 = 1
しかし、2つのタイプの1つがインデックスで、もう1つが範囲であるという質問があります。rangeがインデックス内の範囲クエリであり、indexがすべてのインデックスをスキャンすることは理にかなっています。範囲を広げる方が良いのではないでしょうか?(これは、複合インデックスを使用する場合に発生します。複合インデックスを適用せず、通常のインデックスのみを使用する場合、タイプはすべて範囲です)
!=を使用すると、インデックスが無効になります(mysq8はインデックスを使用します)
mysql8バージョンの場合、インデックスも使用されます
explain select id1 from test19 where id1 !=1
explain select * from test19 where id1 !=1
通常のインデックスを使用する場合、タイプはすべて範囲です
is(not)nullはインデックスを使用できません(mysql 8はインデックスを使用できます)
次の例はすべてmysql8です。
explain select * from test18 where id1 is null
ファジークエリは%で開始できません
explain select * from user where username like "name%"
explain select * from user where username like "%name"
ただし、最初に%を使用する必要がある場合は
、カバーインデックスを使用して次のソリューションを使用できます。
explain select username from user where username like "%name"
explain select password from user where username like "%name" # 非selet 覆盖索引
主キーを見つける
explain select id from user where username like "%name"
インデックス付き列の型変換を防止します
explain select username from user where username = '11'
explain select username from user where username = 11;
またはの使用が少ない(mysql 8またはインデックスが無効にならない)
mysql8はインデックスを無効にしません
explain select password from user where username = '11' or username ='1';
explain select password from user where username = '11' or username ='1';
説明する
+ SQLステートメントについて説明します。
これらのフィールドは、クエリの後に表示されます。これらのフィールドから、
1。テーブルの読み取り順序
2.データ読み取り操作の操作タイプ
3.この行のデータはどのテーブルに表示され
ますか4.クエリはどのタイプを使用しますか
5.可能性のあるインデックス利用される
6.実際に使用され
ているインデックス。7 。インデックス列に一致するフィールドを同じ値で表示し
ます。8 。必要なレコードを見つけるために読み取る必要のある行数を見積もります(少ないほど良い)。
id(テーブルの読み取り順序を取得できます)
explain select * from test16 ,test15,test14
IDが同じ場合、実行順序は上から下になります。つまり、最初にtest16テーブルをクエリし、次にtest15をクエリし、最後にtest14をクエリします。
EXPLAIN SELECT
*
FROM
test16 t16
WHERE
t16.id = (
SELECT
t15.id
FROM
test15 t15
WHERE
t15.id = ( SELECT t14.id FROM test14 t14 ))
サブクエリの場合、IDはインクリメントされ、IDが大きいほど、最初に実行される回数が多くなります。
EXPLAIN SELECT
*
FROM
test16 t16 , test17
WHERE
t16.id = (
SELECT
t15.id
FROM
test15 t15
WHERE
t15.id = ( SELECT t14.id FROM test14 t14 ))
同じIDと異なるIDの両方がある場合。最初に最大のものを実行します。次に、同じシーケンスが実行されます。
Select_type(データ読み取り操作の操作タイプ)
1.シンプル:シンプルな選択クエリ、サブクエリとユニオンは含まれません
2.プライマリ:クエリに複雑なサブパーツが含まれている場合、最も外側のクエリはプライマリとしてマークされ
ます3.サブクエリ:選択中またはラフマンサブクエリ
4.Derived:fromリストに含まれるサブクエリはDerivedとしてマークされ、Mysqlはこれらのサブクエリを再帰的に実行し、結果を一時テーブルに配置します。
5.ユニオン:2番目の選択がユニオンの後に表示される場合、それはユニオンとしてマークされます。from句の
サブクエリにunionが含まれている場合、外側のselectは派生していないとしてマークされます。6.unionResult:Unionテーブルから結果を取得するselectの
例
EXPLAIN SELECT
*
FROM
( SELECT * FROM test15 UNION SELECT * FROM test14 ) ss,
test16
WHERE
ss.id = test16.id
テーブル(操作テーブル名)
この行のデータがどのテーブルに関するものかを表示します
type(クエリで使用されているタイプを示します)
1.システム:テーブルには1行のレコード(システムテーブルと同じ)しかありません。これは、constタイプの特殊なケースです
。2。Const:インデックスで1回検出できることを意味します。constは、一意のインデックスと主キーインデックスを比較するためによく使用されます。1行のデータにしか一致しないため、高速です。
3. Eq_ref:インデックスキーごとの一意のインデックススキャン。テーブル内の1つのレコードのみがそれに一致します。主キーまたは一意のインデックススキャンで一般的に使用されます
4.ref:一意でないインデックススキャン。単一の値に一致するすべての行
を最良から最低まで
返します。5.range:指定された範囲の行のみを取得し、インデックスを使用して行を選択します。(> <between)
6:インデックス:フルインデックススキャン
7:すべて:フルテーブルスキャン
システム> Const> eq_ref> ref> range> index> all
possible_keys(使用できるインデックス)
適用される可能性のあるインデックスを表示しますが、適用されない場合もあります。1つ以上存在する可能性があります。クエリに関係するフィールドにインデックスがある場合は、インデックスが一覧表示されます。
キー(実際に使用されるインデックス)
実際に使用されるインデックス。NULLの場合、インデックスは使用されません。クエリでカバーインデックスが使用されている場合、インデックスはキーリストにのみ表示されます。
カバーするインデックス:インデックスには、クエリする必要のある値が含まれます(カバーされます)。
key_len(インデックスで使用されるバイト数)
使用されるインデックスの長さを示します。インデックスタイプがintの場合、key_len = 5(nullが許可されているため、4 + 1)intがnullでない場合、key_len = 4
ref(等しい値のインデックス列に一致するフィールドを表示します)
インデックスクエリと同等のフィールドを表示します。これは、列または定数(const)の場合があります。
行(目的のレコードを見つけるために読み取る必要のある行数を見積もります)
テーブルの統計とインデックスの選択に従って、必要なレコードを見つけるために読み取る必要のある行数を概算します。
extra(他の列に表示するのに適していないが、非常に重要な追加情報が含まれています)
1.ファイルソートの使用:mysqlは、テーブル内のインデックスの順序に従ってデータを読み取る代わりに、外部インデックスを使用してデータをソートします。mysqlのインデックスでは実行できないソート操作は、ファイルソート
2と呼ばれます。一時テーブルの使用:一時テーブルは中間結果を保存するために使用され、mysqlはクエリ結果をソートするときに一時テーブルを使用します。並べ替えとグループ化で共通
3.インデックスの使用:選択フィールドがカバーインデックスを使用することを示します
4.場所の使用:フィルタリングの場所を使用します
5.結合バッファーの使用:結合テーブルは結合キャッシュを使用します
6.不可能な場所:where句は肯定的は誤りです
ヒストグラム
ヒストグラムがmysql8に追加され、SQLを最適化するための新しいアイデアが提供されます。ヒストグラムは通常、インデックスが作成されておらず、データの一意の値が制限されており、データの量が不均一に分散されているテーブルで使用されます。インデックスを作成することでアクセス速度を向上させることもできますが、このフィールドのインデックスを頻繁に使用しないと、多くのメンテナンスコストを負担することになります。現時点では、ヒストグラムを作成することでメンテナンスコストを大幅に削減できます。ヒストグラムは1回作成するだけで、リアルタイムのメンテナンスは不要です。
ステートメント。ヒストグラムがアクセス速度を向上させることができる理由は、ヒストグラムmysqlのオプティマイザがSQL実行戦略をより適切に選択できるためです。
Analyze table table_name update histogram on table_clomun
MyISamテーブルレベルロック
MyIsamはテーブルレベルのロックをサポートしています。テーブルレベルのロックは2つのタイプに分けられます。1つは共有読み取りロックで、もう1つは排他的書き込みロックです。MyISamエンジンは、読み取り操作よりも書き込み操作の方が重要であると考えているため、ロック待機キューに読み取りロックがある場合でも、書き込みロックは彼の前にランク付けされます。したがって、MyISamは、更新および読み取り操作が多数あるシステムには適していません。ただし、特別な場合には、読み取り中に挿入することが許可されます。(concurrent_insertパラメーターを設定する必要があります)concurrent_insertパラメーターが0の場合。読み取り時に挿入することはできません。1の場合、中央に穴がない場合はテーブルの端に挿入できます。3の場合、穴が開いている場合はテールに挿入できます。
MySQL行ロック
1. InnoDBの行ロックはインデックスに基づいて実装されます。インデックスを介してデータにアクセスしない場合、innodbはすべてのデータをロックします
。2。InnoDBのロックメカニズムと一貫した読み取り戦略は、分離レベルによって異なります。
3. MySQLのリカバリとレプリケーションは、InnoDBのロックメカニズムと一貫した読み取り戦略にも大きな影響を与えます。
4.ロックの競合やデッドロックさえも回避するのは困難です。
//マスタースレーブレプリケーション