mysqlがこの単純な結合クエリで使用する「明らかな」キーを無視するのはなぜですか?

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

  •  03-07-2019
  •  | 
  •  

質問

単純なクエリだと思っていたものがありますが、「永遠に」かかります。私はSQLの最適化が得意ではないので、皆さんにお尋ねできると思いました。

EXPLAINを使用したクエリです:

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

LocaionのクラスのMeta.orderingフィールドを(" name_en&quot ;,)に変更すると、クエリが誤った順序にならないようにクエリが修正されました。

役に立ちましたか?

解決

これらは試行錯誤による傾向がありますが、firms_firmphonenumber.location_idではなくfirms_location.idで注文してみてください。これらは同じ値ですが、MySQLはインデックスを取得する可能性があります。

他のヒント

結合に使用しています。これは、 ref 列の 'citiadmin.firms_location.id' 値です。 WHERE句がなく、ORDER BY句で使用可能なキーのみを反映しているため、 possible_keys および key には表示されません。

クエリを高速化する場合は、 name_en のインデックスを作成してみてください。

場所がないため、結合フィールドのカーディナリティが結合フィールドのカーディナリティよりも高いため、すべてを取得できる可能性があると計算しています。結合でインデックスを使用しても速度は上がりません。そのため、ソートにインデックスを使用するよりも少ない最適化に頼っています。

まず、USEを実行して、指定したインデックスを強制的に使用できます。また、最適化を実行して、カーディナリティーが正しく推定されることを確認してください。 (あなたがINNOを使用していると推測しています。これは一連のランダムな「ダイビング」で推定します。これが実際に知っているMyISAMの場合、なぜカーディナリティがそれと同じように見えるのでしょうか?)

名前などのインデックス付けを行わないでください。MySQLは結合ごとにテーブルごとに1つのインデックスのみを使用し、インデックスはそれを一括します。

データ量は?数行のみの場合、ほとんどのデータベースは、インデックスが何であってもテーブルスキャンを実行します

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top