Domanda

Ho quella che avrei pensato fosse una semplice domanda, ma ci vuole 'per sempre'. Non sono bravo con le ottimizzazioni SQL, quindi ho pensato di potertelo chiedere.

Ecco la query, con 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;

Risultato:

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

Chiavi su posizione_studio:

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

Tasti su numero_firmphon:

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

Mi sembra (per me) che mySQL si rifiuti di usare la chiave primaria della tabella83_location - ma non ho idea del perché.

Qualsiasi aiuto sarebbe molto apprezzato


Modifica dopo la pubblicazione della soluzione

Con l'ordine modificato di:

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;

Risultato:

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

Perché ha deciso di usarli ora? mySQL fa delle strane scelte ... Qualsiasi approfondimento sarebbe di nuovo utile :)


Modifica con dettagli da Django

Inizialmente avevo questi modelli (abbreviati):

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

La modifica del campo Meta.ordering della classe Locaion in (" name_en " ;,) ha corretto la query in modo che non avesse un ordine spurio di.

È stato utile?

Soluzione

Queste cose tendono ad essere per tentativi ed errori, ma prova a ordinare su companies_location.id piuttosto che companies_firmphonenumber.location_id. Hanno lo stesso valore, ma MySQL potrebbe quindi rilevare l'indice.

Altri suggerimenti

Lo sta usando, per il join; questo è il valore 'citiadmin.firms_location.id' nella colonna ref . Non appare in possible_keys e key perché non hai la clausola WHERE e riflette solo le chiavi che ha a disposizione per la clausola ORDER BY.

Se si desidera accelerare la query, provare a indicizzare name_en .

Poiché non c'è dove, e poiché la cardinalità del campo di join è superiore a quella del campo di join, si sta calcolando che potrebbe anche ottenere tutto. L'uso dell'indice sul join non accelera, quindi ricorre alla minore ottimizzazione dell'utilizzo di un indice per l'ordinamento.

Per prima cosa, puoi fare USO per forzarlo a utilizzare l'indice specificato. Inoltre, prova a eseguire un'ottimizzazione per assicurarti che la cardinalità sia stimata correttamente. (Immagino che tu stia utilizzando INNO, che lo stima in una serie di "immersioni" casuali se questo è MyISAM, che in realtà lo sa, quindi mi chiedo perché la cardinalità assomigli a così.)

Non preoccuparti di indicizzare il nome o ecc. MySQL userà mai solo un indice per tabella per join, e l'indice lo farà semplicemente aumentare.

quanti dati? se solo poche righe, la maggior parte dei database eseguirà solo una scansione della tabella, indipendentemente dagli indici che hai

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top