1

これについて同様の質問があることは知っていますが、このクエリの理由について特定のクエリ/質問があります

EXPLAIN SELECT DISTINCT RSubdomain FROM R_Subdomains WHERE EmploymentState IN (0,1) AND RPhone='7853932120' 

この出力の説明を教えてください

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  RSubdomains index   NULL    RSubdomain  767 NULL    3278    Using where

RSubdomains を使用し、RSubdomain にインデックスを付ける

しかし、EmploymentState/RPhone に複合インデックスを追加すると

説明からこの出力を取得します

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  RSubdomains range   EmploymentState EmploymentState 67  NULL        2   Using where; Using temporary

RSubdomainsでdistinctを取り除くと、説明出力からUsing tempが削除されます...しかし、得られないのは、複合キーを追加すると(そしてRSubdomainでキーを保持すると)、distinctが終了する理由です一時テーブルを使用していて、ここではどのインデックス スキーマが優れていますか? 結合されたキーでスキャンされる行の量ははるかに少ないことがわかりますが、クエリは範囲型であり、速度も低下します。

4

1 に答える 1

1

Q: なぜ...個別に一時テーブルを使用することになるのですか?

MySQL は、述語 (WHERE 句) を満たす行を見つけるために、インデックスの範囲スキャン (つまり、インデックス ブロックの読み取り) を実行しています。次に、MySQL はRSubdomain基になるテーブルから列の値を検索する必要があります (インデックスでは使用できません)。重複を排除するために、MySQLRSubdomainは取得された値をスキャンする必要があります。「Using temp」は、MySQL が結果セットをマテリアライズしていることを示します。これは、後続のステップで処理されます。(おそらく、これRSubdomainは取得された値のセットです。DISTINCT を考えると、MySQL は実際に RSubdomain を主キーまたは一意キーとして一時テーブルを作成し、重複しない値のみを挿入している可能性があります。

最初のケースでは、行が順番に取得されているように見えますRSubdomain(おそらく、クラスター キーの最初の列です)。つまり、MySQL はすべての値を比較する必要はありませんRSubdomain。値を「スキップ」できるかどうかを判断するために、最後に取得した値が現在取得している値と一致するかどうかを確認するだけで済みます。

Q: ここではどのインデックス スキーマが優れていますか?

クエリに最適なインデックスは、おそらくカバリング インデックスです。

... ON R_Subdomains (RPhone, EmploymentState, RSubdomain)

ただし、3278 行しかないため、パフォーマンスの違いはほとんど見られません。

ファローアップ

残念ながら、MySQL は、他の RDBMS で提供されるタイプのインスツルメンテーションを提供しません (リソースと待機の実際のタイミングを提供する Oracle イベント 10046 SQL トレースなど)。

MySQL は、利用可能な場合はインデックスを使用することを選択しているため、おそらくこれが最も効率的な計画です。最高の効率を得るために、私は OPTIMIZE TABLE 操作を実行します (動的フォーマットの InnoDB テーブルと MyISAM テーブルの場合、特に行の長さを変更する DELETE と UPDATE など、かなりの数の DML 変更があった場合...)少なくとも、インデックス統計が最新であることを保証します。

DISTINCT の代わりに GROUP BY を実行する同等のステートメントの計画を比較したい場合があります。

SELECT r.RSubdomain
  FROM R_Subdomains r
 WHERE r.EmploymentState IN (0,1)
   AND r.RPhone='7853932120'
 GROUP
    BY r.Subdomain

最適なパフォーマンスを得るには、RPhone を先頭列とするカバリング インデックスを使用します。これは、RPhone 列のカーディナリティ (一意の値に近い) に関する仮定に基づいており、EmploymentState 列のわずかな異なる値とは対照的です。そのカバリング インデックスにより、最高のパフォーマンスが得られます。つまり、検査が必要な行が最も迅速に削除されます。

ただし、数千行しかないため、パフォーマンスの違いを確認するのは困難です。クエリが何百万もの行を調べていた場合、違いが見られる可能性が高く、良好なパフォーマンスの鍵は、検査する必要がある行の数を制限することです。

于 2013-11-09T00:03:47.917 に答える