了解mysql解释

时间:2009-07-21 08:38:19

标签: mysql database database-design optimization

所以,我从未理解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解释说不需要查询。唉,似乎你无法从explain语句中获得足够的信息,而你需要原始的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

2 个答案:

答案 0 :(得分:17)

保罗:

  

<强> eq_ref

     

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

     

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;
  

<强> REF

     

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

     

ref可用于使用=或&lt; =&gt;进行比较的索引列运营商。在以下示例中,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

如果您可以发布正在永久的查询,我可以帮助查明减慢速度的问题。另外,请指明您对永远的定义。另外,如果你能提供你的“SHOW CREATE TABLE xxx;”这些表的语句,我可以帮助您尽可能地优化您的查询。

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

答案 1 :(得分:4)

您的查询似乎处理(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