我在MySQL(5.5.31)中有一个约有20M行的表。下面的查询:DISTINCT导致全表扫描
SELECT DISTINCT mytable.name name FROM mytable
LEFT JOIN mytable_c ON mytable_c.id_c = mytable.id
WHERE mytable.deleted = 0 ORDER BY mytable.date_modified DESC LIMIT 0,21
引起全表扫描,以讲解说type
是ALL
和额外的信息是Using where; Using temporary; Using filesort
。解释的结果:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE mytable ALL NULL NULL NULL NULL 19001156 Using where; Using temporary; Using filesort
1 SIMPLE mytable_c eq_ref PRIMARY PRIMARY 108 mytable.id 1 Using index
没有加入解释的样子:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE mytable index NULL mytablemod 9 NULL 21 Using where; Using temporary
id_c
是mytable_c
和mytable_c
主键不具备的每一行不止一行在mytable
。 date_modified
已编入索引。但看起来像MySQL不明白这一点。如果我删除了DISTINCT子句,那么explain
使用索引,并且只触及21行就像预期的那样。如果我删除连接它也这样做。如果没有连接的全表扫描,有没有办法让它工作? explain
显示mysql知道它只需要mytable_c
中的一行,它正在使用主键,但仍在mytable
上进行全面扫描。
DISTINCT是由于ORM系统生成查询的原因,在ORM系统中可能会有多行可能由JOIN生成的情况,但SELECT字段的值将始终是唯一的(即,如果JOIN是针对多个 - 值链接只有在每个连接行中相同的字段将在SELECT中)。
对于没有列选择的表,您有一个外连接。我不明白。 – Strawberry
@Strawberry这个查询有点简单,但它*仍*导致全表扫描。这是奇怪的部分 - 无论我是否包含其他表的字段,都会发生全表扫描。 – StasM
试图回答这种问题而没有看到a)解释和b)正确的DDLs是愚蠢的。 (并不是说即使有这些信息我也能做得更好!) – Strawberry