¿Por qué mysql ignora la clave 'obvia' para usar en esta simple consulta de combinación?

StackOverflow https://stackoverflow.com/questions/804258

  •  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.

¿Fue útil?

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top