Por que é mysql ignorando a chave 'óbvio' para uso nesta simples consulta de junção?
-
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.
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