【问题标题】:understanding mysql explain了解mysql解释
【发布时间】:2010-11-12 13:54:15
【问题描述】:

所以,我从来没有理解 MySQL 的解释。我理解您应该在 possible_keys 列中至少有一个条目以使用索引的粗略概念,并且简单的查询更好。但是 ref 和 eq_ref 有什么区别呢?优化查询的最佳方法是什么。

例如,这是我的最新查询,我试图弄清楚为什么它需要永远(从django 模型生成):

+----+-------------+---------------------+--------+-----------------------------------------------------------+---------------------------------+---------+--------------------------------------+------+---------------------------------+
| id | select_type | table               | type   | possible_keys                                             | key                             | key_len | ref                                  | rows | Extra                           |
+----+-------------+---------------------+--------+-----------------------------------------------------------+---------------------------------+---------+--------------------------------------+------+---------------------------------+
|  1 | SIMPLE      | T6                  | ref    | yourock_achiever_achievement_id,yourock_achiever_alias_id | yourock_achiever_alias_id       | 4       | const                                |  244 | Using temporary; Using filesort |
|  1 | SIMPLE      | T5                  | eq_ref | PRIMARY                                                   | PRIMARY                         | 4       | paul.T6.achievement_id               |    1 | Using index                     |
|  1 | SIMPLE      | T4                  | ref    | yourock_achiever_achievement_id,yourock_achiever_alias_id | yourock_achiever_achievement_id | 4       | paul.T6.achievement_id               |  298 |                                 |
|  1 | SIMPLE      | yourock_alias       | eq_ref | PRIMARY                                                   | PRIMARY                         | 4       | paul.T4.alias_id                     |    1 | Using index                     |
|  1 | SIMPLE      | yourock_achiever    | ref    | yourock_achiever_achievement_id,yourock_achiever_alias_id | yourock_achiever_alias_id       | 4       | paul.T4.alias_id                     |  152 |                                 |
|  1 | SIMPLE      | yourock_achievement | eq_ref | PRIMARY                                                   | PRIMARY                         | 4       | paul.yourock_achiever.achievement_id |    1 |                                 |
+----+-------------+---------------------+--------+-----------------------------------------------------------+---------------------------------+---------+--------------------------------------+------+---------------------------------+
6 rows in set (0.00 sec)

我曾希望对 mysql 有足够的了解,说明不需要该查询。唉,您似乎无法从解释语句中获得足够的信息,而您需要原始 SQL。查询:

SELECT  `yourock_achievement`.`id`,
        `yourock_achievement`.`modified`,
        `yourock_achievement`.`created`,
        `yourock_achievement`.`string_id`,
        `yourock_achievement`.`owner_id`,
        `yourock_achievement`.`name`,
        `yourock_achievement`.`description`,
        `yourock_achievement`.`owner_points`,
        `yourock_achievement`.`url`,
        `yourock_achievement`.`remote_image`,
        `yourock_achievement`.`image`,
        `yourock_achievement`.`parent_achievement_id`,
        `yourock_achievement`.`slug`,
        `yourock_achievement`.`true_points`
FROM    `yourock_achievement`
INNER JOIN
        `yourock_achiever`
ON       `yourock_achievement`.`id` = `yourock_achiever`.`achievement_id`
INNER JOIN
        `yourock_alias`
ON      `yourock_achiever`.`alias_id` = `yourock_alias`.`id`
INNER JOIN
        `yourock_achiever` T4
ON      `yourock_alias`.`id` = T4.`alias_id`
INNER JOIN
        `yourock_achievement` T5
ON      T4.`achievement_id` = T5.`id`
INNER JOIN
        `yourock_achiever` T6
ON      T5.`id` = T6.`achievement_id`
WHERE
        T6.`alias_id` = 6
ORDER BY
        `yourock_achievement`.`modified` DESC

【问题讨论】:

  • 不太重要,但我建议将其用于 mysql 性能监控和调整:jetprofiler.com
  • 能否请您发布查询本身?
  • 您能否计算COUNT(*) 返回的行数,如我的帖子中所述?
  • 我尝试运行该查询 10 分钟,但没有结果。如果您愿意,我可以计算各个表中的条目。
  • 好的,12 分钟就完成了。 349285347 行......是的,我想这回答了这个问题:( 应该有一个小组在某个地方,不知道 django 是如何把它扔出去的。

标签: mysql database database-design optimization


【解决方案1】:

保罗:

eq_ref

对于之前表中的每个行组合,都会从该表中读取一行。 除了 system 和 const 类型之外,这是最好的连接类型。当连接使用索引的所有部分并且索引是 PRIMARY KEY 或 UNIQUE 索引时使用它。 p>

eq_ref 可用于使用 = 运算符比较的索引列。比较值可以是常量或使用在此表之前读取的表中的列的表达式。在以下示例中,MySQL 可以使用 eq_ref 连接来处理 ref_table:

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;

参考

对于先前表中的每个行组合,都将从该表中读取具有匹配索引值的所有行。 如果连接只使用键的最左前缀或者如果键不是 PRIMARY KEY 或 UNIQUE 索引(换句话说,如果连接不能根据键值选择单行),则使用 ref强>。如果使用的键只匹配几行,这是一个很好的连接类型。

ref 可用于使用 = 或 运算符比较的索引列。在以下示例中,MySQL 可以使用 ref join 来处理 ref_table:

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;

这些是从 MySQL 手册中逐字复制的:http://dev.mysql.com/doc/refman/5.0/en/using-explain.html

如果您可以发布您的查询永远,我可以帮助查明是什么导致它变慢。另外,请说明您对 forever 的定义是什么。另外,如果你能提供你的“SHOW CREATE TABLE xxx;”这些表的语句,我可以帮助尽可能优化您的查询。

作为一个可能的改进点,我立即跳出来的是“使用临时;使用文件排序;”。这意味着创建了一个临时表来满足查询(不一定是坏事),并且无法从索引中检索到您指定的 GROUP BY/ORDER BY,从而导致 filesort .

【讨论】:

    【解决方案2】:

    您的查询似乎处理了(244 * 298 * 152) = 11,052,224 记录,根据Using temporary; Using filesort 需要对其进行排序。

    这可能需要很长时间。

    如果您在此处发布您的查询,我们可能会以某种方式对其进行优化。

    更新:

    您的查询确实执行了许多嵌套循环,并且似乎产生了许多需要排序的值。

    您能否运行以下查询:

    SELECT  COUNT(*)
    FROM    `yourock_achievement`
    INNER JOIN
            `yourock_achiever`
    ON       `yourock_achievement`.`id` = `yourock_achiever`.`achievement_id`
    INNER JOIN
            `yourock_alias`
    ON      `yourock_achiever`.`alias_id` = `yourock_alias`.`id`
    INNER JOIN
            `yourock_achiever` T4
    ON      `yourock_alias`.`id` = T4.`alias_id`
    INNER JOIN
            `yourock_achievement` T5
    ON      T4.`achievement_id` = T5.`id`
    INNER JOIN
            `yourock_achiever` T6
    ON      T5.`id` = T6.`achievement_id`
    WHERE
            T6.`alias_id` = 6
    

    【讨论】:

    • 这并不完全准确。这些数字并不意味着查询返回那么多记录。事实上,它表明 MySQL 必须读取这么多行来确定要返回的行。
    • @hobodave:因为我们在这里没有看到额外的Using where,所以可以安全地假设所有这些行实际上都会被返回(尤其是缺少关于查询的其他信息)。
    • 不能假设。一个简单的“LIMIT 1”,除其他外,反驳了你的假设。
    • @hobodave:在这个意义上你是对的,它们不一定需要返回给客户,但它们仍然需要返回到分拣机/区分器(根据@ 987654325@).
    • @hobodave:我最好将其称为“处理”以避免混淆。
    猜你喜欢
    • 2012-09-12
    • 2023-03-10
    • 2020-02-18
    • 1970-01-01
    • 2014-06-05
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 2012-02-17
    相关资源
    最近更新 更多