Por que é mysql ignorando a chave 'óbvio' para uso nesta simples consulta de junção?

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu tenho o que eu pensei que seria uma consulta simples, mas é preciso 'para sempre'. Eu não sou grande com otimizações SQL, então eu pensei que eu poderia pedir a vocês.

Aqui está a consulta, com 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, ''

Chaves na firms_location:

Keyname                 Type    Unique  Packed  Field   Cardinality
PRIMARY                    BTREE    Yes     No      id      65818
firms_location_name_en     BTREE    No      No      name_en 65818

Chaves na firms_firmphonenumber:

Keyname                     Type  Unique Packed  Field       Cardinality
PRIMARY                         BTREE Yes    No      id          85088
firms_firmphonenumber_firm_id   BTREE No     No      location_id 85088

Parece (para mim) que o MySQL se recusa a usar a chave primária da tabela firms_location -. Mas não tenho idéia do porquê

Qualquer ajuda seria muito apreciado.


Editar após a solução postada

Com a ordem alterada 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 que decidir usá-los agora? mySQL faz algumas escolhas estranhas ... Qualquer visão ajudaria novamente:)


Editar com detalhe de Django

Originalmente, eu tinha esses modelos (abreviado):

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")

Alterar campo Meta.ordering de classe do locaion para ("name_en", ) fixa a consulta para não ter o fim espúrio por.

Foi útil?

Solução

Essas coisas tendem a ser por tentativa e erro, mas tente ordenação em firms_location.id em vez de firms_firmphonenumber.location_id. Eles são o mesmo valor, mas o MySQL pode, em seguida, pegar no índice.

Outras dicas

É a usá-lo, para a junção; que é o valor 'citiadmin.firms_location.id' na coluna ref. Ele não está aparecendo na possible_keys e key porque você não tem cláusula WHERE e só está refletindo chaves que tem disponível para a cláusula ORDER BY.

Se você quiser acelerar a sua consulta, tente indexar name_en.

Porque não há aí, e porque a cardinalidade do campo de associação é maior do que a do campo juntar, é calculando que ele poderia muito bem ter tudo. Usando o índice na junção não irá acelerar-se que, por isso é recorrer ao menor otimização da utilização de um índice para classificação.

Em primeiro lugar, você pode fazer USE para forçá-lo a usar o índice que você especificar. Além disso, tente fazer uma optimize para garantir que a cardinalidade está corretamente estimado. (Eu estou supondo que você está usando INNO, que estima-lo em uma série de "mergulhos" aleatórios;. Se isso é MyISAM, que realmente sabe, então eu me pergunto por que os olhares cardinalidade como faz)

Não se preocupe indexar o nome ou etc. MySQL irá utilizar apenas um índice por tabela por juntar-se, sempre, e o índice será apenas a granel-lo.

a quantidade de dados? se apenas algumas linhas, a maioria dos bancos de dados só vai fazer uma mesa de digitalização não importa o que você tem índices

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top