当使用索引时,Mysql解释查询类型为“ALL”

时间:2013-12-20 09:48:15

标签: mysql sql indexing query-optimization explain

我在Mysql中运行了一个查询,如下所示:

EXPLAIN
SELECT *
FROM(
        SELECT *  # Select Number 2
        FROM post
        WHERE   parentid = 13
        ORDER BY time, id
        LIMIT 1, 10
    ) post13_childs
JOIN post post13_childs_childs
ON post13_childs_childs.parentid = post13_childs.id

结果是:

id |select_type  |table               |type |possible_keys  |key      |key_len  |ref              |rows    |Extra
1  |PRIMARY      |<derived2>          |ALL  | NULL          | NULL    |NULL     |NULL             |10      |
1  |PRIMARY      |post13_childs_childs|ref  |parentid       |parentid |9        |post13_childs.id |10      |Using where
2  |DERIVED      |post                |ALL  |parentid       |parentid |9        |                 |153153  |Using where; Using filesort

这意味着它使用了索引parentid,但扫描了由ALL153153引起的所有行。 为什么索引无法帮助Full Scannig

虽然如果我运行派生查询(选择#2)单独,如下所示:

Explain
SELECT * FROM post  
WHERE parentid=13
ORDER BY time , id
LIMIT 1,10

结果是理想的:

id |select_type  |table  |type |possible_keys  |key      |key_len  |ref  |rows    |Extra
1  |SIMPLE       |post   |ref  |parentid       |parentid |9        |const|41      |Using where; Using filesort

编辑:

post包含以下索引:

  1. id(PRIMARY)
  2. parentId的
  3. time,id(timeid)
  4. 总行数 - &gt; 141280.
    13parentid=13)的儿童数量 - &gt; 41个
    11523的儿童数量 - &gt; 10119

    当我添加(parent,time,id)的索引时,第一个查询的问题将通过13的explin输出解决 - &gt; 40行,输入:ref
    11523 - &gt; 19538行,类型:ref !!!这意味着在我限制前10行的同时检查11423的所有子行。

2 个答案:

答案 0 :(得分:7)

您的子查询:

    SELECT *  # Select Number 2
    FROM post
    WHERE   parentid = 13
    ORDER BY time, id
    LIMIT 1, 10;

这明确提到了三列,加上所有其他列你有三个索引。以下是它们的使用方法:

  • id(PRIMARY) - 这个索引没用。虽然在order by子句中提到过,但它是第二个条件
  • parentid - 此索引可用于满足where子句。但是,在拉出正确的数据后,则需要明确排序。
  • time,id(timeid) - 此索引可用于排序,具有较大的BUT。 MySQL可以扫描索引以获得正确顺序的所有内容。但它必须逐行检查parentid上的条件是否得到满足。

只是为了介绍为什么优化很难。如果您有少量数据(比如表格适合一页或两页),那么全表扫描后跟排序可能就好了。如果大多数parentid值为13,则第二个索引可能是最差情况。如果表不适合内存,那么第三个将非常慢(称为页面颠簸)。

此子查询的正确索引是满足where子句并允许排序的索引。该指数为parentid, time, id。这不是覆盖索引(除非这些是表中的所有列)。但是由于limit子句,它应该将实际行的命中数减少到10。

请注意,对于完整查询,您需要parentid上的索引。并且,幸运的是,parentid, time, id上的索引算作这样的索引。因此,您可以删除该索引。 time, id索引可能不是必需的,除非您需要其他查询。

您的查询也只过滤那些自己有“孩子”的“孩子”。很可能不会返回任何行。你真的打算left outer join吗?

作为最终评论。我假设此查询是您的真实查询的简化。查询从两个表中提取所有列 - 这两个表是相同的。也就是说,您将从相同的表中获取重复的列名。您应该有列别名以更好地定义列。

答案 1 :(得分:0)

执行任何索引无法帮助的ORDER BY都可能导致性能下降。对于内部查询,我将在(parentID,time,id)上设置覆盖索引,以便WHERE和ORDER BY子句都可以使用索引。由于parentID也是连接后缀的基础,因此去那里并且速度非常快。