Warum ignoriert mysql die ‚offensichtliche‘ Schlüssel in diesem einfach zu verwenden Abfrage beitreten?

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

  •  03-07-2019
  •  | 
  •  

Frage

Ich habe, was ich gedacht hatte wäre eine einfache Abfrage sein, aber es dauert ‚ewig‘. Ich bin nicht gut mit SQL-Optimierungen, so dachte ich, ich könnte euch fragen.

Hier ist die Abfrage mit 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;

Ergebnis:

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

Tasten auf firms_location:

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

Tasten auf firms_firmphonenumber:

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

Es scheint (mir), dass mySQL der firms_location Tabelle Primärschlüssel zu verwenden, weigert sich -. Aber ich habe keine Ahnung, warum

Jede Hilfe wäre viel geschätzt.


Edit nach Lösung geschrieben

Mit der geänderten Reihenfolge durch:

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;

Ergebnis:

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

Warum haben sie die Entscheidung, diese jetzt zu benutzen? mySQL einige seltsame Entscheidungen trifft ... Einsicht würde helfen, wieder:)


Bearbeiten mit Detail von django

Ursprünglich hatte ich diese (abgekürzt) Modelle:

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

die locaion der Klasse Meta.ordering Feld fixiert ("name_en", ) die Abfrage ändern nicht durch die falsche Reihenfolge haben.

War es hilfreich?

Lösung

Diese Dinge sind in der Regel durch Versuch und Irrtum zu sein, sondern versuchen, die Bestellung auf firms_location.id statt firms_firmphonenumber.location_id. Sie sind der gleiche Wert, aber MySQL kann dann auf den Index aufzunehmen.

Andere Tipps

Es ist mit ihm, für die beitreten; das ist der 'citiadmin.firms_location.id' Wert in der ref Spalte. Es wird nicht angezeigt, in possible_keys und key, weil Sie nicht haben WHERE-Klausel und es nur ist reflektierenden Schlüssel für die ORDER BY-Klausel zur Verfügung hat.

Wenn Sie Ihre Abfrage zu beschleunigen, versuchen Indizierung name_en.

Da es keine wo ist, und weil die Mächtigkeit des Verknüpfungsfeld höher als als der Verbindungsbereich, es ist die Berechnung, dass es auch alles bekommen könnte. Unter Verwendung des Index für die beitreten werden, dass nicht beschleunigen, so dass es den Rückgriff auf die geringere Optimierung der einen Index für die Sortierung verwendet wird.

Als erstes können Sie USE tun, um es zu zwingen, den Index zu verwenden, die Sie angeben. Versuchen Sie auch, eine optimize tun, um sicherzustellen, dass die Mächtigkeit richtig geschätzt. (Ich vermute, Sie INNO verwenden, die es in einer Reihe von zufälligen „Tauchgänge“, schätzt;., Wenn dies MyISAM ist, der wirklich weiß, dann frage ich mich, warum die Mächtigkeit aussieht, wie es der Fall ist)

Sie sich nicht die Mühe, den Namen der Indizierung oder usw. MySQL nur einen Index pro Tabelle verwenden pro beitreten, überhaupt, und der Index wird bulk es einfach auf.

, wie viele Daten? wenn nur wenige Zeilen, die meisten Datenbanken nur einen Tabellenscan tun, egal welche Indizes Sie haben

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top