所以,我从未理解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
答案 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