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'

IE。虽然第一个查询仅扫描 1586 行,但此查询扫描超过 56074 行

尽管事实上第二个查询应该返回第一个查询结果的子集。

IE。在第一个查询的 1586 个结果中,返回 c.range_field <= 10 的结果。

有没有办法修改这个查询,因为第二个查询的结果只是第一个查询结果的子集,所以扫描的行数将是 <=1586

4

2 回答 2

1

从性能的角度来看,第二个查询是第一个查询的子集这一事实并不重要。

在第一个查询中,没有涉及 c 表的过滤器,而在第二个查询中,有一个 on c.range_fieldUsing index正如您在第一个解释计划(扫描次数较少)。在第二个解释计划中,MYSQL 必须使用公共数据库 hd 块计算结果集,这是一个缓慢的操作(全表扫描:行被逐一读取并以这种方式评估)。

您的解决方案是评估将该列包含在第二个解释计划的列中注释的索引c.range_field之一的可能性。possible keysc

于 2013-11-11T07:05:49.197 回答
0

由于您正在过滤c.range_field并且def c是子句中的第三个表FROM,因此过滤发生在三个表的连接集的结果集上,因为没有索引。我建议您按照 Sebas 的回答并在c.range_field.

我自己会使用的另一种方法是设置def为驾驶台。这意味着,FROM以表开头您的子句def,最好后跟jkl. 这将过滤第一个和第二个表上的行,然后将它们与第三个和第四个表连接起来。

于 2013-11-11T07:13:33.443 回答