简体   繁体   English

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

[英]Mysql Explain Query with type “ALL” when an index is used

I ran a query in Mysql like below: 我在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

and the result was: 结果是:

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

This means it used the index parentid but scaned all rows due to ALL and 153153 . 这意味着它使用了索引parentid但是由于ALL153153而扫描了所有行。 Why could not the index help to not Full Scannig ? 为什么索引无法帮助Full Scannig

Although if i run the derived query (Select #2) alone like below: 虽然如果我单独运行派生查询(选择#2) 如下所示:

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

the result would be desired: 结果是理想的:

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

Edit: 编辑:

The table post has these indexes: 表格post有以下索引:

  1. id (PRIMARY) id(PRIMARY)
  2. parentid parentId的
  3. time, id (timeid) 时间,id(timeid)

count of total rows --> 141280. 总行数 - > 141280。
count of children of 13 ( parentid=13 ) --> 41 13岁儿童的数量( parentid=13 ) - > 41
count of children of 11523 --> 10119 儿童11523 - > 10119

When i add index of (parent,time,id) , problem of first query would be solved by the explin output for 13 --> 40 rows, type:ref 当我添加(parent,time,id)索引(parent,time,id)第一个查询的问题将通过13 - > 40行的explin输出来解决,输入:ref
and for 11523 --> 19538 rows, type:ref!!! 对于11523 - > 19538行,请输入:ref !!! this Means all children rows of 11423 is examined while i limited first 10 rows. 这意味着检查所有11423行的子行,而我限制前10行。

Your subquery: 你的子查询:

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

This mentions three columns explicitly, plus all the rest of the columns You have three indexes. 这显然提到了三列,加上所有其他列你有三个索引。 Here is how they can be used: 以下是它们的使用方法:

  • id (PRIMARY) -- This index is useless. id(PRIMARY) - 这个索引没用。 Although mentioned in the order by clause, it is the second condition 虽然在order by子句中提到,但它是第二个条件
  • parentid -- This index can be used for satisfying the where clause. parentid - 此索引可用于满足where子句。 However, after the correct data is pulled, it then would need to be sorted explicitly. 但是,在拉出正确的数据之后,需要明确地对其进行排序。
  • time, id (timeid) -- This index can be used for the sort, with a big BUT. time,id(timeid) - 这个索引可以用于排序,具有很大的BUT。 MySQL can scan the index to get everything in the right order. MySQL可以扫描索引以获得正确顺序的所有内容。 But it will have to check, row-by-row, whether the condition on parentid is met. 但它必须逐行检查是否满足了parentid的条件。

Just to introduce why optimization is hard. 只是为了介绍为什么优化很难。 If you have a small amount of data (say the table fits on one or two pages), then a full table scan followed by a sort is probably fine. 如果您有少量数据(比如表格适合一页或两页),那么全表扫描后跟排序可能就好了。 If most of the parentid values are 13 , then the second index could be a worst case. 如果大多数parentid值是13 ,那么第二个索引可能是最坏的情况。 If the table does not fit into memory, then the third would be incredibly slow (something called page thrashing ). 如果表不适合内存,那么第三个将非常慢(称为页面颠簸 )。

The correct index for this subquery is one that satisfies the where clause and allows ordering. 此子查询的正确索引是满足where子句并允许排序的索引。 That index is parentid, time, id . 该指数是parentid, time, id This is not a covering index (unless these are all the columns in the table). 这不是覆盖索引(除非这些是表中的所有列)。 But it should reduce the number of hits to actual rows to 10 because of the limit clause. 但是由于limit子句,它应该将实际行的命中数减少到10。

Note that for the complete query, you want an index on parentid . 请注意,对于完整查询,您需要parentid上的索引。 And, happily, an index on parentid, time, id counts as such an index. 并且,幸运的是,关于parentid, time, id的索引算作这样的索引。 So, you can remove that index. 因此,您可以删除该索引。 The time, id index is probably not necessary, unless you need that for other queries. time, id索引可能不是必需的,除非您需要其他查询。

Your query is also filtering only those "children" that have "children" themselves. 您的查询也只过滤那些自己有“孩子”的“孩子”。 It is quite possible that no rows will be returned. 很可能不会返回任何行。 Do you really intend a left outer join ? 你真的想要一个left outer join吗?

As a final comment. 作为最后的评论。 I assume that this query is a simplification of your real query. 我假设此查询是您的真实查询的简化。 The query is pulling all columns from two tables -- and those two tables are the same. 查询从两个表中提取所有列 - 这两个表是相同的。 That is, you will be getting duplicate column names from identical tables. 也就是说,您将从相同的表中获取重复的列名。 You should have column aliases to better define the columns. 您应该有列别名以更好地定义列。

Doing an ORDER BY that is not helped by any index can regularly kill performance. 执行任何索引无法帮助的ORDER BY都可能导致性能下降。 For the inner query, I would have a covering index on (parentID, time, id ) so that both the WHERE and ORDER BY clauses can utilize the index. 对于内部查询,我将在(parentID,time,id)上设置覆盖索引,以便WHERE和ORDER BY子句都可以使用索引。 Since the parentID is also the basis of the join afterwords, it should be good to go there to and be quite fast. 由于parentID也是连接后缀的基础,所以去那里并且非常快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM