Mysqlボトムレイヤーの実行方法を知っていますか?

  • 実際の開発では、フィールドに基づいて並べ替えて結果を表示する必要があることは間違いありませんが、MySQLの下部でorder byがどのように実行されるかを本当に理解していますか?
  • 市が蘇州であるすべての人々の名前を照会し、それらを名前でソートして、最初の1000人の名前と年齢を返す場合は、次のSQLステートメントをどのように記述しますか?
  • 最初にユーザーテーブルを作成します。sqlステートメントは次のとおりです。
CREATE TABLE user (
id int(11) NOT NULL,
city varchar(16) NOT NULL,
name varchar(16) NOT NULL,
age int(11) NOT NULL,
PRIMARY KEY (id),
KEY city (city)
) ENGINE=InnoDB;
  • 上記の要件のSQLクエリステートメントは次のとおりです。
select city,name,age from user where city='苏州' order by name limit 1000;
  • 誰もがこのsqlクエリステートメントを記述できると思いますが、Mysqlの下部にあるその実行プロセスを理解していますか?今日、チェン氏は、このSQLステートメントの実行方法と、実行プロセスに影響を与えるパラメーターについて話しました。
  • この記事は、詳しく説明するために次の部分に分かれています。フルフィールドソートROWIDソートフルフィールドソートVS ROWIDソートソートを回避する方法

すべてのフィールドを並べ替え

  • 以前にインデックスについて説明したので、テーブル全体のスキャンを回避できるため、cityフィールドにインデックスを追加しました。もちろん、cityフィールドは非常に小さく、文字列のインデックスを考慮する必要はありません。
  • このとき、Explainはこのクエリステートメントの実行を分析するために使用され、結果は次のようになります。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • Extraフィールドでfilesortを使用すると、ソートが必要であることを示します。MySQLは、sort_bufferと呼ばれるソート用の各スレッドにメモリの一部を割り当てます。
  • インデックスはクエリに使用されるので、次に示すように、単純に都市のインデックスツリーの構造を描画します。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • 上の図からわかるように、city = 'Suzhou'を満たすのはID3からIDXまでのレコードです。
  • 通常、このSQLステートメントの実行フローは次のとおりです。
  1. sort_bufferを初期化し、name、city、およびageの3つのフィールドを必ず入れてください。
  2. インデックスcityから、条件city = 'Suzhou'を満たす最初の主キーIDを見つけます。図ではID3です。
  3. 主キーIDインデックスに移動して行全体を取得し、3つのフィールドname、city、およびageの値を取得して、sort_bufferに格納します。
  4. インデックスシティから次のレコードの主キーIDを取得します。
  5. 図の例では、cityの値がクエリの条件を満たさなくなるまで手順3と4を繰り返します。対応する主キーIDはIDXです。
  6. フィールド名に従ってsort_bufferのデータをすばやくソートします。
  7. 最初の1000行を取得し、ソート結果に従ってクライアントに戻ります。
  • この並べ替えプロセスを全フィールド並べ替えと呼びます。実行のフローチャートは次のとおりです。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • 並べ替えに必要なメモリとパラメータsort_buffer_sizeに応じて、図での名前による並べ替えのアクションはメモリ内で完了するか、外部の並べ替えが必要になる場合があります。
  • sort_buffer_size:これは、ソートのためにMySQLによって開かれたメモリ(sort_buffer)のサイズです。ソートするデータの量がsort_buffer_size未満の場合、ソートはメモリ内で行われます。ただし、ソートデータの量が多すぎて保存できない場合は、ディスクの一時ファイルを使用してソートを支援する必要があります。

ROWIDソート

  • 上記のアルゴリズムプロセスでは、元のテーブルデータのみが1回読み込まれ、残りの操作はsort_bufferと一時ファイルで実行されました。ただし、このアルゴリズムには問題があります。クエリによって返されるフィールドが多い場合、sort_bufferに配置するにはフィールドが多すぎるため、同時にメモリに配置できる行の数は非常に少なく、多くの一時ファイルに分割する必要があります。悪いでしょう。
  • したがって、単一の線が大きい場合、この方法は十分に効率的ではありません。
  • max_length_for_sort_dataパラメーターを変更して、別のアルゴリズムを使用できます。max_length_for_sort_dataは、ソートに使用される行データの長さを特に制御するMySQLのパラメーターです。つまり、単一の行の長さがこの値を超えると、MySQLは単一の行が大きすぎると見なし、アルゴリズムを変更する必要があることを意味します。
  • 都市、名前、年齢の3つのフィールドの合計の長さは36です。max_length_for_sort_dataを16に設定して、計算プロセスを見てみましょう。set SQLステートメントは次のとおりです。
SET max_length_for_sort_data = 16;
  • 新しいアルゴリズムは、sort_bufferのフィールド、並べ替える列(nameフィールド)と主キーIDのみを入れます。
  • ただし、現在のところ、cityフィールドとageフィールドの値がないため、並べ替えの結果を直接返すことはできません。実行プロセス全体は次のようになります。
  1. sort_bufferを初期化します。名前とIDの2つのフィールドを必ず入れてください。
  2. インデックスcityから、条件city = 'Suzhou'を満たす最初の主キーIDを見つけます。図ではID3です。
  3. 行全体を主キーidインデックスに移動し、2つのフィールドnameとidを取得して、sort_bufferに格納します。インデックスシティから次のレコードの主キーIDを取得します。
  4. 図の例では、cityの値がクエリの条件を満たさなくなるまで手順3と4を繰り返します。対応する主キーIDはIDXです。
  5. フィールド名に従ってsort_bufferのデータをすばやくソートします。
  6. 並べ替えの結果を反復処理し、最初の1000行を取得し、idの値に従って元のテーブルに戻り、都市、名前、年齢の3つのフィールドを取り出して、クライアントに返します。
  7. この実行プロセスの概略図は次のとおりです。ROWIDソートと呼びます。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

  • 全フィールドの並べ替えと比較して、ROWIDの並べ替えには、テーブルに戻るクエリがもう1つあります。これは、手順7のクエリの主キーインデックスツリーです。

全フィールドソートとROWIDソート

  • MySQLがソートメモリが小さすぎてソート効率に影響を与えることが本当に心配されている場合は、ROWIDソートアルゴリズムが使用されるため、ソートプロセス中に一度により多くの行をソートできますが、元のテーブルに戻ってデータをフェッチする必要があります。
  • MySQLがメモリが十分大きいと判断した場合、最初に全フィールドの並べ替えを選択し、必要なフィールドをsort_bufferに入れます。これにより、並べ替え後、クエリ結果がメモリから直接返され、データをフェッチするために元のテーブルに戻る必要がなくなります。
  • これは、MySQLの設計思想も反映しています。十分なメモリがある場合は、ディスクアクセスを最小限に抑えるためにより多くのメモリを使用する必要があります。
  • InnoDBテーブルの場合、ROWIDソートはテーブルへのバックをさらに必要とし、ディスク読み取りを引き起こすため、推奨されません。

ソートを回避する方法

  • 実際、すべてのorder byステートメントがソート操作を必要とするわけではありません。上記で分析した実行プロセスから、MySQLが一時テーブルを生成し、一時テーブルでソート操作を実行する必要がある理由は、元のデータが順序付けされていないためであることがわかります。
  • 都市のインデックスから取得された行が名前の増加によって自然に並べ替えられることが保証できる場合、それらを再度並べ替えることはできませんか?
  • したがって、結合インデックスを考えて、(都市、名前)結合インデックスを作成します。sqlステートメントは次のとおりです。
alter table user add index city_user(city, name);
  • このときのインデックスツリーは次のとおりです。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • このインデックスでは、ツリー検索メソッドを使用して、city = 'Suzhou'を満たす最初のレコードを見つけることができます。さらに、次のレコードを順番に取得するトラバーサルプロセスで、値が杭州の場合、nameの値を注文する必要があります。
  • 上の図によると、クエリプロセス全体は次のようになります。インデックス(市、名前)から、条件を満たす市=「蘇州」を満たす最初の主キーIDを見つけます。行全体を主キーIDインデックスに移動し、3つのフィールドname、city、およびageの値を取得して、結果セットの一部として直接返します。インデックス(市、名前)からレコードの主キーIDを削除します。1000番目のレコードが見つかるまで手順2と3を繰り返します。または、city = 'Suzhou'条件が満たされないときにループが終了します。
  • 対応するフローチャートは次のとおりです。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • ご覧のとおり、このクエリプロセスでは一時テーブルや並べ替えは必要ありません。次に、説明の結果を使用して確認します。
    画像
  • 図からわかるように、「追加」フィールドに「ファイルソートの使用」はありません。つまり、ソートは必要ありません。(city、name)ジョイントインデックス自体が順序付けられているため、このクエリは4000行すべてを読み取る必要はありません。条件を満たす最初の1000レコードが見つかれば、終了できます。つまり、この例では、1000回スキャンするだけで済みます。
  • これで十分ですか?このクエリを最適化できますか?
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • 友達はインデックスをカバーすることを覚えていますか?インデックスをカバーすることの利点は、テーブルを再度クエリすることを避けることです。
  • (city、name、age)ジョイントインデックスを作成して、上記のクエリステートメントが実行されたときに対象のインデックスを使用できるようにし、テーブルへのクエリが戻されないようにします。SQLステートメントは次のとおりです。
讲真,这两款idea插件,能治愈你英语不好的病alter table user add index city_user_age(city, name, age);
  • このときの実行フローチャートは次のとおりです。
Mysqlボトムレイヤーの実行方法を知っていますか?

 

 

  • もちろん、インデックスをカバーすると効率が向上しますが、インデックスの維持にもコストがかかるため、トレードオフがあります。

おすすめ

転載: www.cnblogs.com/CQqfjy/p/12717509.html