【问题标题】:Mysql Explain Query with type "ALL" when an index is used使用索引时,Mysql Explain Query 类型为“ALL”
【发布时间】:2014-01-09 03:26:08
【问题描述】:

我在 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(主要)
  2. 父代
  3. 时间,id (timeid)

总行数 --> 141280.
13 (parentid=13) 的孩子数量 --> 41
11523 的孩子数 --> 10119

当我添加 (parent,time,id) 的索引时,第一次查询的问题将通过 13 的 explin 输出解决 --> 40 行,输入:ref
对于11523 --> 19538 行,输入:ref!!!这意味着检查11423 的所有子行,而我限制了前 10 行。

【问题讨论】:

  • 您需要帮助改进和优化此查询吗?如果是这样,我们需要查看整个查询(及其解释)
  • @Strawberry,对不起。我现在编辑并写了细节。
  • 尝试为(parentid, time, id) 创建索引。进一步参考mysqlperformanceblog.com/2006/09/01/…
  • 你不能利用派生表中的索引......
  • @Meherzad,为什么?真的吗?是一个可用的参考。

标签: mysql sql indexing query-optimization explain


【解决方案1】:

您的子查询:

    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,那么第二个索引可能是最坏 的情况。如果表不适合内存,那么第三个会非常慢(称为 page thrashing)。

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

请注意,对于完整的查询,您需要parentid 上的索引。而且,令人高兴的是,parentid, time, id 上的索引也算作这样的索引。因此,您可以删除该索引。 time, id 索引可能不是必需的,除非您在其他查询中需要它。

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

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

【讨论】:

  • tnx 回复。我添加了索引parentid, time, id 但是...(查看我对上述问题的编辑,我现在更改了)
【解决方案2】:

在没有任何索引帮助的情况下执行 ORDER BY 会经常影响性能。对于内部查询,我将在 (parentID, time, id ) 上有一个覆盖索引,以便 WHERE 和 ORDER BY 子句都可以使用该索引。由于 parentID 也是 join afterwords 的基础,所以去那里应该很好,而且速度很快。

【讨论】:

  • @ahoo,不,现在是一对 (time,id),你需要包含 Parent ID,所以索引应该是 (PARENTID, TIME, ID)
  • 当我索引(parentID, time, id )时,解释结果的列rows输出19538(和类型:ref)。由于LIMIT 子句,我预计为 10。
  • @ahoo,我建议删除单个 parentID 和 (timeid, id ) 以避免对引擎造成混淆,因为在索引的第一个位置具有 parentID 的一个索引与您的立场相同- 单独索引,但同时将时间和 id 作为第二和第三位置将解析 order by 子句。
  • parentID 被定义为外键。所有外键也是索引。而且我认为不能删除它的索引。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 2016-03-07
相关资源
最近更新 更多