MySQLのクエリのコストと範囲の範囲

上の記事のMySQLは、NULL IS NULLではありません,! = あなたはインデックスを使用することはできませんか?クラップス!しつこいで,! =インデックスは、これらの条件を使用することも可能です、NULL NULLではありませんWHERE句に表示されるクエリのコストの問題を強調し、クエリ多くの学生は、コスト・オア・ナッシングの考え方に反映させるために、我々今日少しの深いNAGを戻ってきます。

B +ツリー構造

私たちは、と言うInnoDBのストレージエンジン、データテーブルはインデックスを構築よりも、私たち以上の各いわゆるB +ツリーに格納されている、それはマルチB +ツリーの確立に相当します。

  • B +ツリーに対応するクラスタ化インデックスのために、ユーザー・レコード記憶リーフノード(クラスタ化インデックスレコードへのいわゆるユーザー・レコード、意味は、すべてのユーザー定義の列は、いくつかの組み込みの列含有)、及びこれら主キーの値に従って昇順にクラスタ化インデックスレコード。

  • セカンダリインデックスのB +ツリーに対応するリーフノードが加入者記録が完了していない保存(いわゆる不完全ユーザレコードをインデックスレコードを指すが、2つだけの列を含み、主キーインデックス)とに応じて、これらの2つの索引レコード昇順でインデックス列の値。

我々は、テーブルにレコードの数を格納され、どのように多くのレコードは、B +ツリーの各リーフノードに含まれる(B +ツリー二つ対応するインデックスB +ツリーに対応するクラスタ化インデックスを含む「一人一人を」注意してください) 。

ここでは、例を与えます:

CREATE TABLE t (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    key1 INT,
    common_field VARCHAR(100),
    PRIMARY KEY (id),
    KEY idx_key1 (key1)
) Engine=InnoDB CHARSET=utf8;
复制代码

このテーブルは、2つのインデックス(すなわち、2件のB +ツリー)を含有します。

  • id列ベースクラスタ化インデックスキーに対応します。

  • key1設立され、二次索引列idx_key1

私たちは、テーブルに一部のレコードを挿入します。

INSERT INTO t VALUES
    (1, 30, 'b'),
    (2, 80, 'b'),
    (3, 23, 'b'),
    (4, NULL, 'b'),
    (5, 11, 'b'),
    (6, 53, 'b'),
    (7, 63, 'b'),
    (8, NULL, 'b'),
    (9, 99, 'b'),
    (10, 12, 'b'),
    (11, 66, 'b'),
    (12, NULL, 'b'),
    (13, 66, 'b'),
    (14, 30, 'b'),
    (15, 11, 'b'),
    (16, 90, 'b');
复制代码

だから今s1、テーブルのクラスタ化インデックス図はこれです:

image_1dg2m0lab11lhlib1eq7g5dius2d.png-77.1kB

s1概略図の表は、このセカンダリインデックスです。

image_1dg2m44tf1o4cv3nro1oul111n2q.png-66.9kB

図から分かるように、値のNULL二次インデックスレコードは、所定のInnoDB叔父として設計された左端のB +ツリーに配置されています。

我々は、フィールドの可能な最小値であることがヌルSQLを定義します。

それは私が考える、あるNULL値が最小です。

ヒント:私たちは、このようなと、このような簡素化を行い、我々はページの構造を省略するB +ツリー構造を赦し、すべてのノードが省略されている(だけ三角形またはビデオ)、録画リストが省略されている間、これらは、それが指定されたインデックスキーに従ってソート強調表示されているリーフノードを記録するためにのみ示されている場合のように見えるように描かれたこの記事の焦点では​​ないからです。

我々は今、次のクエリを実行するとしましょう:

SELECT * FROM t WHERE key1 = 53;
复制代码

プロセスへの文を実行すると、以下の通り:

image_1dg2me2kg1tvh1ohlera1ge712837.png-80.5kB

このプロセスが何であるかを言葉で説明します。

  • 二つの第一のインデックスによってidx_key1対応B+迅速ツリー検索するkey1列値53ピース2つの索引レコード。

  • 次に、2つの主キーインデックスレコード、すなわち6実行する回表動作を、見つけるために、すなわち、クラスタ化インデックスid列は、6クラスタ化インデックスレコード。

ヒント:B +は、ノードレコードはB +ツリーインデックスによってリーフノードのレコードを検索することが非常に速く、ソート昇順でキーに従っている葉。しかし、我々は、これらの事のページディレクトリをノード内にガミガミていなかったので、それはリーフノードのレコードを処理するためにB +ツリーインデックスは、詳細をしつこいされていないことで配置され、これらのものは、実際にMySQLはそれがどのように動作するかである「、次のとおりですから、 GENER MySQLの「ナゲッツの小冊子を理解することは、あまりにも詳細に伝えます。

次のようにこのクエリ:

SELECT * FROM t WHERE key1 > 20 AND key1 < 50;
复制代码

その実装の概略図はこれです:

image_1dg2ohcgd1psqaut11levmk1oki3k.png-88.7kB

言葉で表現することはこれです:

  • 二つの第一のインデックスによりidx_key1に対応B+素早く満たすツリー見つけるkey1 > 20図1に示されている最初のレコードを、私達のkey123二つの主要なキーのインデックスに基づいて、レコード、および3バックテーブルに操作を実行し、得完全なユーザーレコードがクライアントに送信された後。

  • 前の手順は、次に取得されるkey1の列値23の二次インデックスが記録されnext_record、次の二次インデックスレコードが見出さ即ち属性のkey1列の値30、ユーザの完全な記録を与えるために記録後、再びテーブルに操作を実行しますクライアントに送信されます。

  • そして、前のステップ取得見つけkey1た列の値を30次のレコード2つのインデックスレコードに、レコードkey1列の値も30、操作はクライアントに送信された完全なユーザーを記録したバックテーブルに続けています。

  • そして、前のステップ取得見つけkey1列値30次のレコード2のインデックスレコード、レコード内key1の列の値を53満たしていない、key1 < 50このクエリが終了されるように、条件を。

ステップはまた、上側から見ることができる:複数のセカンダリインデックスレコードをスキャンする、テーブルに戻って実行される複数の操作レコードをスキャンする必要が二次インデックスは合計の割合が一定の範囲に達する記録する場合は、オプティマイザが全表スキャンクエリを使用することを選択することが可能であるが実行される(極端な例では、二次インデックスレコードのすべては、すべての意志をスキャンすることですバックセカンダリインデックスの記録実行操作テーブル、明らかではないとして、直接フルテーブルスキャン)。

ヒント:むしろ、定量的な分析よりも、まだここに私たちのステレオタイプのコストを分析します。プロセスの定量的分析は複雑ですが、書かれた小さな冊子があり、興味のある学生は見ることができます。

だから今結論はこれです:インデックスを使用することができ、クエリの条件が低い、低い総レコードの割合が、その後、低コストを説明するかどうかセカンダリインデックスレコードをスキャンする必要があるかどうかを決定し、それがセカンダリインデックスを使用して行うことができますクエリ、または全表スキャンを使用します

特定のクエリ分析

私たちは、それぞれを見てWHERE句に現れIS NULLIS NOT NULL!=これらの条件オプティマイザが決定を下すためにどのようにあるとき。

のNULLケースです

このクエリは、例えば:

SELECT * FROM t WHERE key1 IS NULL;
复制代码

オプティマイザ実際にクエリを実行する前に、あなたが最初に調査し、インデックスの少量を訪問するkey1中で[NULL, NULL]どのように多くのレコードこのセクション:

image_1dg2r7u6s1ms3162d1erp52immf8c.png-28.9kB

ヒント:[NULL、NULL]この間隔は間隔だけNULL値を表します。

セカンダリインデックスをスキャンする必要があり、調査を通じてOptimizerがされたレコードバーの合計数の割合を記録し3/16、実行計画は、この画面を使用するように、セカンダリインデックスの使用は、クエリより信頼性の高い実行すると感じているidx_key1クエリを実行します:

image_1dg2pki1r12stmt419ae1ep7125a5e.png-40.2kB

場合は、NULLではありません

このクエリは、例えば:

SELECT * FROM t WHERE key1 IS NOT NULL;
复制代码

オプティマイザは、実際にクエリを実行する前に、あなたは最初に見て、インデックスの少量を訪問するどのように多く、この期間内のレコード:key1(NULL, +∞)

image_1dg2rbnspvavkk710k0adkhpua9.png-28.9kB

ヒント:我々は、すべてあなたが-∞よりも小さいと考えることができ、最小としてNULL治療のためにここにいます。また(NULL、+∞)開区間であることの間隔を注意してください、それはNULL値が含まれていないことを意味します。

セカンダリインデックスをスキャンする必要があり、調査を通じてOptimizerは、レコードバーの合計数の割合がされて記録され13/16、明らかにこの比率で非常に大きなされているので、オプティマイザはクエリを実行する方法の全表スキャンを使用することにしました:

image_1dg2pu5kc79oh5c1m2vj131inu6l.png-36.4kB

利用するにはどのようにIS NOT NULLセカンダリインデックスにそれを使用してクエリの条件?ようにこれは、テーブルに沿って、簡単ではありませんIS NOT NULL過去最低の条件がリストに、私たちは次のことを実行することができません。

UPDATE t SET key1 = NULL WHERE key1 < 80;
复制代码

したがって、このクエリを実行するために行きます:

SELECT * FROM t WHERE key1 IS NOT NULL;
复制代码

オプティマイザ実際にクエリを実行する前に、それは最初に見て、インデックスの少量を訪問するkey1(NULL, +∞)、この区間内には、どのように多くの記録::

image_1dg2remb8gts2j6rjnvuic8b6.png-29.3kB

セカンダリインデックスをスキャンする必要があり、調査を通じてOptimizerがされたレコードバーの合計数の割合を記録し3/16、実行計画は、この画面を使用するように、セカンダリインデックスの使用は、クエリより信頼性の高い実行すると感じているidx_key1クエリを実行します:

image_1dg2q4glvgea1kt01q71h5q1b2p72.png-40KB

!=ケースの

このクエリは、例えば:

SELECT * FROM t WHERE key1 != 80;
复制代码

オプティマイザは、実際にクエリを実行する前に、あなたが最初に調査し、インデックスの少量を訪問するkey1(NULL, 80)および(80, +∞)これらの2つの領域がどのように多くの記録しました:

image_1dg2rst6h1egu1cue1idnbk67s1bj.png-31.5kB

セカンダリインデックスをスキャンする必要があり、調査を通じてOptimizerがされたレコードバーの合計数の割合を記録し2/16、実行計画は、この画面を使用するように、セカンダリインデックスの使用は、クエリより信頼性の高い実行すると感じているidx_key1クエリを実行します:

image_1dg2pki1r12stmt419ae1ep7125a5e.png-40.2kB

ちょっと待って!なぜの実施計画rowsの列は3それはありますか?これはどのような地獄、市民権のための条件を満たし、明らかに2つだけの記録です。ハハ、私たちが見つかりました。各区間の条件を満たしたレコードのどのような数を設定します。

  • (NULL, 80)間隔0のレコードが条件を満たしてkey1 != 80

  • (80, +∞)2つの記録間隔を満たす条件がありますkey1 != 80

しかし、オプティマイザの設計は、所定の叔父がここにあります:与えられた範囲区間内のレコードの数が急にそれを破る0、1の条件を満たしたときそれは、実際のオプティマイザは考えている(NULL, 80)。この間隔の条件を満たしているレコードの範囲がありますkey1 != 80したがって、実装計画rows列のみ示しています3

ヒント:以下オプティマイザ自身の叔父のデザインは、0から条件の範囲の一定の間隔に一致するレコードの数が急に(読みかつ迅速に、見て理解できる1にそれを破るためにそれを説明するときに、 )スキップ:MySQLのオプティマイザは、精度が保証されないことに基づいて「空のセット」0行の推定値が常に正確であるとの結果を返すことが信じているようだ、とそれは我々がとにかくべきロックの読み取りのために、あったとしても。ネクストキーロックを設定するには、検索を実行します。MySQLは仮定を行わないことを確認した値に1を追加!

概要

これまでのところ、我々は別々に分析しているIS NULLIS NOT NULL!=これらの三つの条件を照会すると、どのような状況の下で実行するためにセカンダリインデックスを使用することで、コアの結論は次のとおりです。意思決定の実施計画のコストは、使用するどのようなクエリーとは関係ありませんCOが到達最適化は、これらの範囲内の二つのインデックスレコードの合計の割合は、レコードの合計数のこれらの間隔の何調査で、次にレコードを、それぞれ、二次インデックスを使用するいくつかの可能な範囲を分割し、そしてための最初のセクションの範囲でありますとき値、オプティマイザは、全表スキャンの賛成で、セカンダリインデックスを使用してクエリを実行放棄します。

ヒント:実際には、また、意思決定のオプティマイザに影響を与える範囲間隔部門のあまり、セカンダリインデックスを使用することを決定したクエリオプティマイザを実行するリスクを軽減します、の条件であまりにも多くのパラメータがあると言います。さらに、2つの方法が個数の範囲内のオプティマイザ調査レコードインデックス間隔があり、一つは(本実施形態では、データがあまり正確である場合には、長い時間がデータの一部の偏差であろう)は、いわゆるインデックスダイブであります一つは、それが、ある調査統計を行うために、インデックス統計に依存している(このように統計が非常に正確である、時々偏差は超素晴らしいです)、とにかく、どんなにどの方法、オプティマイザする各範囲間隔計算するインデックスの数を記録します。小さな冊子での調査について、これら二つの方法は、詳細なアルゴリズムを与えられた当然、ビットやり過ぎ公共記事の番号を書き、かなりのスペースを占めています。

余談

疲れ記事を書く、時にはあなたは、多くの修正の結果の後ろに実際にある非常に滑らかな読み取りを、感じます。あなたが良いと感じた場合は前方に助けてください、それ非常に感謝〜。ここで私のパブリック数時間から子牛を引い程度の時間に、内側より呉服技術「我々は小さなカエルです」、歓迎の注意:

おすすめ

転載: juejin.im/post/5d5f4b3a51882540b16f35be