为什么mysql忽略了在这个简单的连接查询中使用的“明显”键?

时间:2009-04-29 21:02:43

标签: django-models mysql indexing

我有我认为简单的查询,但需要“永远”。我对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, ''

firm_location上的键:

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

firm_firmphonenumber上的键:

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

似乎(对我而言)mySQL拒绝使用firm_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", )会将查询修改为不具有虚假顺序。

4 个答案:

答案 0 :(得分:4)

这些事情往往是通过反复试验,但尝试在firm_location.id而不是firm_firmphonenumber.location_id上订购。它们是相同的值,但MySQL可能会接受索引。

答案 1 :(得分:1)

它正在使用它,用于连接;这是'citiadmin.firms_location.id'列中的ref值。它没有出现在possible_keyskey中,因为您没有WHERE子句,它只反映了ORDER BY子句可用的键。

如果您想加快查询速度,请尝试编制索引name_en

答案 2 :(得分:1)

因为没有地方,并且因为连接字段的基数高于连接字段的基数,所以它计算它也可以获得所有内容。使用连接上的索引不会加快速度,因此使用索引进行排序的优化程度较低。

首先,您可以执行USE以强制它使用您指定的索引。此外,尝试进行优化以确保正确估计基数。 (我猜你正在使用INNO,它在一系列随机“潜水”中估计它;如果这是MyISAM,它实际上知道,那么我想知道为什么基数看起来像它。)

不要费心索引名称等.MySQL每个联接每个表只会使用一个索引,索引只会将其批量化。

答案 3 :(得分:0)

数据有多少?如果只有几行,大多数数据库只会进行表扫描,无论你有什么索引