¿Por qué mysql ignora la clave 'obvia' para usar en esta simple consulta de combinación?
-
03-07-2019 - |
Pregunta
Tengo lo que pensé que sería una consulta simple, pero toma 'para siempre'. No soy bueno con las optimizaciones de SQL, así que pensé que podría preguntarles.
Aquí está la consulta, con EXPLICAR:
EXPLAIN SELECT *
FROM `firms_firmphonenumber`
INNER JOIN `firms_location` ON (
`firms_firmphonenumber`.`location_id` = `firms_location`.`id`
)
ORDER BY
`firms_location`.`name_en` ASC,
`firms_firmphonenumber`.`location_id` ASC LIMIT 100;
Resultado:
id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1, 'SIMPLE', 'firms_location', 'ALL', 'PRIMARY', '', '', '', 73030, 'Using temporary; Using filesort'
1, 'SIMPLE', 'firms_firmphonenumber', 'ref', 'firms_firmphonenumber_firm_id', 'firms_firmphonenumber_firm_id', '4', 'citiadmin.firms_location.id', 1, ''
Claves en la ubicación de las empresas:
Keyname Type Unique Packed Field Cardinality
PRIMARY BTREE Yes No id 65818
firms_location_name_en BTREE No No name_en 65818
Claves en firmas_firmphonenumber:
Keyname Type Unique Packed Field Cardinality
PRIMARY BTREE Yes No id 85088
firms_firmphonenumber_firm_id BTREE No No location_id 85088
A mi parecer, mySQL se niega a usar la clave principal de la tabla de ubicación de las empresas, pero no tengo idea de por qué.
Cualquier ayuda sería mucho apreciada.
Editar después de la solución publicada
Con el orden alterado por:
EXPLAIN SELECT *
FROM `firms_firmphonenumber`
INNER JOIN `firms_location` ON (
`firms_firmphonenumber`.`location_id` = `firms_location`.`id`
)
ORDER BY
`firms_location`.`name_en` ASC,
`firms_location`.id ASC LIMIT 100;
#`firms_firmphonenumber`.`location_id` ASC LIMIT 100;
Resultado:
"id","select_type","table","type","possible_keys","key","key_len","ref","rows","Extra"
1,"SIMPLE","firms_location","index","PRIMARY","firms_location_name_en","767","",100,""
1,"SIMPLE","firms_firmphonenumber","ref","firms_firmphonenumber_firm_id","firms_firmphonenumber_firm_id","4","citiadmin.firms_location.id",1,""
¿Por qué decidió usar estos ahora? mySQL toma algunas decisiones extrañas ... Cualquier idea ayudaría de nuevo :)
Editar con detalle desde django
Originalmente, tenía estos modelos (abreviados):
class Location(models.Model):
id = models.AutoField(primary_key=True)
name_en = models.CharField(max_length=255, db_index=True)
class Meta:
ordering = ("name_en", "id")
class FirmPhoneNumber(models.Model):
location = models.ForeignKey(Location, db_index=True)
number = PhoneNumberField(db_index=True)
class Meta:
ordering = ("location", "number")
Al cambiar el campo de Meta.ordering de la clase de Locaion a (" name_en " ;,)
se corrigió la consulta para no tener el pedido no deseado por.
Solución
Estas cosas tienden a ser por prueba y error, pero intente ordenar en firmas_location.id en lugar de firmas_firmphonenumber.location_id. Son del mismo valor, pero MySQL puede aparecer en el índice.
Otros consejos
Lo está utilizando, para la unión; ese es el valor 'citiadmin.firms_location.id'
en la columna ref
. No aparece en possible_keys
y key
porque no tiene una cláusula WHERE y solo refleja las claves que tiene disponibles para la cláusula ORDER BY.
Si desea acelerar su consulta, intente indexar name_en
.
Debido a que no hay dónde, y porque la cardinalidad del campo de unión es mayor que la del campo de unión, se calcula que podría obtener todo. El uso del índice en la unión no acelerará eso, por lo que está recurriendo a la menor optimización del uso de un índice para la clasificación.
Primero, puede hacer USE para forzarlo a usar el índice que especifique. Además, intente hacer una optimización para asegurarse de que la cardinalidad se estima correctamente. (Supongo que está usando INNO, que lo estima en una serie de "inmersiones aleatorias"; si esto es MyISAM, que realmente sabe, entonces me pregunto por qué se ve la cardinalidad como lo hace).
No se moleste en indexar el nombre, etc. MySQL utilizará solo un índice por tabla por unión, y el índice simplemente lo agrupará.
¿cuántos datos? si solo unas pocas filas, la mayoría de las bases de datos solo escanearán una tabla sin importar los índices que tenga