2

私がそうするとしましょう

EXPLAIN SELECT * FROM xyz e
            JOIN abc cs ON e.rss = 'text' AND e.rdd = cs.xid
            JOIN def c ON cs.cid = c.xid
            JOIN jkl s ON c.sid = s.nid
          WHERE s.flag = 0;

これにより、次のことが明らかになります。

1, 'SIMPLE', 's', 'ref', 'PRIMARY,Index_8', 'x1', '1', 'const', 1586, 'Using index; Using temporary'
1, 'SIMPLE', 'c', 'ref', 'PRIMARY,sid', 'x2', '4', 's.nid', 40, 'Using index'
1, 'SIMPLE', 'cs', 'ref', 'PRIMARY,cid', 'x3', '4', 'c.nid', 1, 'Using index'
1, 'SIMPLE', 'e', 'ref', 'rss,rdd', 'x4', '141', 'const,cs.nid', 12, 'Using where; Using index; Distinct'

しかし、私がそうするとします

EXPLAIN SELECT * FROM xyz e
            JOIN abc cs ON e.rss = 'text' AND e.rdd = cs.xid
            JOIN def c ON cs.cid = c.xid
            JOIN jkl s ON c.sid = s.nid
          WHERE s.flag = 0 AND c.range_field <= 10;

これは明らかになるだろう

1, 'SIMPLE', 'c', 'ALL', 'PRIMARY,school_nid,Index_5', '', '', '', 56074, 'Using where; Using temporary'
1, 'SIMPLE', 's', 'eq_ref', 'PRIMARY,Index_8', 'PRIMARY', '4', 'c.school_nid', 1, 'Using where'
1, 'SIMPLE', 'cs', 'ref', 'PRIMARY,cid', 'x3', '4', 'c.nid', 1, 'Using index'
1, 'SIMPLE', 'e', 'ref', 'rss,rdd', 'x4', '141', 'const,cs.nid', 12, 'Using where; Using index; Distinct'

すなわち。最初のクエリは 1586 行しかスキャンしていませんが、これは 56074 行をスキャンしています

これは、2 番目のクエリが最初のクエリの結果の SUBSET を返すはずであるにもかかわらずです。

すなわち。最初のクエリの 1586 の結果のうち、c.range_field <= 10 を持つものを返します。

この2番目のクエリの結果は最初のクエリの結果のサブセットにすぎないため、スキャンされる行数が1586以下になるようにこのクエリを変更する方法はありますか?

4

2 に答える 2

1

2 番目のクエリが 1 番目のクエリのサブセットであるという事実は、パフォーマンスの観点からは問題になりません。

最初のクエリでは、c テーブルに関連するフィルターはありませんが、2 番目のクエリでは 1 つc.range_fieldです。最初の説明プラン ( ) でわかるようにUsing index、最初のクエリはインデックスのみを使用して結果セットを計算できます。これは高速な操作です (インデックスから、mysql は必要な行の場所を推測し、これらの行のみを読み取ることができます。スキャンの量が少ない)。2 番目の説明計画では、MYSQL は共通データベース hd ブロックを使用して結果セットを計算する必要がありますが、これは低速な操作です (完全なテーブル スキャン: 行は 1 つずつ読み取られ、そのように評価されます)。

解決策は、2 番目の説明計画の列でコメントされているインデックスc.range_fieldの 1 つに列を含める可能性を評価することです。possible keysc

于 2013-11-11T07:05:49.197 に答える