2009-07-21 24 views
18

Por lo tanto, nunca he entendido la explicación de MySQL. Entiendo los conceptos generales de que debe tener al menos una entrada en la columna possible_keys para que use un índice, y que las consultas simples son mejores. Pero, ¿cuál es la diferencia entre ref y eq_ref? ¿Cuál es la mejor manera de optimizar las consultas?entendiendo mysql explain

Por ejemplo, esta es mi última consulta que estoy tratando de averiguar por qué se necesita siempre (generado a partir de modelos 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) 

Tenía la esperanza de aprender lo suficiente sobre MySQL explicar que la consulta no sería necesario. Por desgracia, parece que no se puede obtener suficiente información de la declaración de explicación y se necesita el SQL sin formato. Consulta:

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

No del todo hasta el punto, pero recomiendo esto para la supervisión del rendimiento de MySQL y puesta a punto: http://www.jetprofiler.com/ –

+0

Podría usted por favor, publique la consulta en sí? – Quassnoi

+0

Consulta SQL publicada –

Respuesta

17

Pablo:

eq_ref

Una fila se lee de esta tabla para cada combinación de filas de las tablas anteriores. Además del sistema y los tipos const, este es el mejor tipo de combinación posible. Se usa cuando todas las partes de un índice son utilizadas por la unión y el índice es PRIMARY KEY o UNIQUE index.

eq_ref se puede usar para columnas indexadas que se comparan con el operador =. El valor de comparación puede ser una constante o una expresión que utiliza columnas de tablas que se leen antes de esta tabla. En los siguientes ejemplos, MySQL puede utilizar un eq_ref unirse para procesar 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

Todas las filas con valores de adaptación de índices se leen a partir de esta tabla para cada combinación de filas de las tablas anteriores. ref se usa si la combinación utiliza solo un prefijo situado más a la izquierda de la clave o si la clave no es PRIMARY KEY o UNIQUE index (en otras palabras, si la unión no puede seleccionar una sola fila según el valor de la clave). Si la clave que se utiliza coincide solo con algunas filas, este es un buen tipo de combinación.

ref se puede utilizar para columnas indexadas que se comparan con el operador = o < =>. En los siguientes ejemplos, MySQL puede utilizar un ref unen para procesar 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; 

Estos son copiados textualmente de la manual de MySQL: http://dev.mysql.com/doc/refman/5.0/en/using-explain.html

Si usted puede publicar su consulta que se está llevando a siempre , Podría ayudar a identificar qué lo está frenando. Además, especifique cuál es su definición de para siempre. Además, si pudiera proporcionar su "MOSTRAR CREAR TABLA xxx;" declaraciones para estas tablas, podría ayudar a optimizar su consulta tanto como sea posible.

Lo que salta a la vista de inmediato ya que un posible punto de mejora es el "Uso temporal; Uso de filesort;".Esto significa que se creó una tabla temporal para satisfacer la consulta (no necesariamente algo malo), y que GROUP BY/ORDER BY que usted designó no pudo recuperarse de un índice, lo que resultó en un archivo de .

+1

No copie textualmente del manual –

4

La consulta parece procesar (244 * 298 * 152) = 11,052,224 registros, que según Using temporary; Using filesort deben ser ordenados.

Esto puede llevar mucho tiempo.

Si publica su consulta aquí, probablemente podamos optimizarla de alguna manera.

Actualización:

se consulta de hecho hace una serie de bucles anidados y parece producir una gran cantidad de valores que deben ser ordenados a continuación.

Podría por favor, ejecute la siguiente consulta:

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 
+0

Esto no es del todo exacto. los números no significan que la consulta devuelve tantos registros. De hecho, designa que MySQL tiene que leer esta cantidad de filas para determinar a cuál devolver. – hobodave

+0

@hobodave: dado que no vemos 'Usar dónde 'aquí, será seguro asumir que todas estas filas serán de hecho devueltas (especialmente sin otra información en la consulta). – Quassnoi

+0

No se puede asumir. Un simple "LIMIT 1", entre otras cosas, refuta su suposición. – hobodave

Cuestiones relacionadas