Почему mysql игнорирует "очевидный" ключ для использования в этом простом запросе объединения?

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

  •  03-07-2019
  •  | 
  •  

Вопрос

У меня есть то, что, как я думал, будет простым запросом, но это занимает "целую вечность".Я не силен в оптимизации SQL, поэтому подумал, что могу спросить вас, ребята.

Вот запрос с ОБЪЯСНЕНИЕМ:

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;

Результат:

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, ''

Ключи от firms_location:

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

Ключи на firms_firmphonenumber:

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

Кажется (мне), что MySQL отказывается использовать первичный ключ таблицы firms_location, но я понятия не имею, почему.

Любая помощь была бы многое оценен по достоинству.


Редактировать после публикации решения

С измененным порядком по:

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;

Результат:

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

Почему он решил использовать их сейчас?MySQL делает несколько странных выборов...Любое понимание снова помогло бы :)


Редактировать с подробностями из django

Изначально у меня были эти (сокращенные) модели:

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

Изменение поля Meta.ordering в классе Locaion на ("name_en", ) исправлено, что запрос не имел ложного порядка by.

Это было полезно?

Решение

Обычно это делается методом проб и ошибок, но попробуйте сделать заказ на firms_location.id, а не на firms_firmphonenumber.location_id.Это одно и то же значение, но затем MySQL может использовать индекс.

Другие советы

Он использует его для объединения;это тот самый 'citiadmin.firms_location.id' ценность в ref колонна.Это не появляется в possible_keys и key потому что у вас нет предложения WHERE, и оно отражает только ключи, доступные для предложения ORDER BY.

Если вы хотите ускорить свой запрос, попробуйте выполнить индексацию name_en.

Поскольку нигде не указано where, и поскольку мощность поля join выше, чем у поля joining, он рассчитывает, что с таким же успехом может получить все.Использование индекса в соединении не ускорит это, поэтому приходится прибегать к меньшей оптимизации использования индекса для сортировки.

Во-первых, вы можете выполнить USE, чтобы заставить его использовать указанный вами индекс.Кроме того, попробуйте выполнить оптимизацию, чтобы убедиться, что мощность оценена правильно.(Я предполагаю, что вы используете INNO, который оценивает это в серии случайных "погружений".;если это MyISAM, который действительно знает, то мне интересно, почему мощность выглядит именно так.)

Не утруждайте себя индексацией имени и т.д.MySQL будет использовать только один индекс для каждой таблицы при каждом объединении, и индекс просто увеличит его объем.

сколько данных?если всего несколько строк, большинство баз данных просто выполнят сканирование таблицы, независимо от того, какие у вас индексы

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top