我在MySQL中有这个表:
Table: city
Columns:
ID int(11) AI PK
Name char(35)
CountryCode char(3)
District char(20)
Population int(11)
我想在CountryCode订购时使用索引,所以我在这个列上创建了索引:
Index: CountryCode
Definition:
Type BTREE
Unique No
Columns CountryCode
为什么 EXPLAIN EXTENDED SELECT * FROM city ORDER BY CountryCode; 不使用索引:
| id: 1
| select type: SIMPLE
| table: city
| partitions: NULL
| type: ALL
| possible_keys: NULL
| key: NULL
| key_len: NULL
| ref: NULL
| rows: 4188
| filtered: 100.00
| Extra: Using filesort
和 EXPLAIN EXTENDED SELECT id FROM world.city ORDER BY CountryCode; 使用索引:
| id: 1
| select type: SIMPLE
| table: city
| partitions: NULL
| type: index
| possible_keys: NULL
| key: CountryCode
| key_len: 3
| ref: null
| rows: 4188
| filtered: 100.00
| Extra: Using index
如何更改此行为 - 即在第一个示例中添加索引用法?
答案 0 :(得分:3)
不是问题。第一个查询使用索引而不是以更快运行。
首先,让我们剖析第二个查询。显然你正在使用InnoDB。这意味着INDEX(country_code)
确实是INDEX(country_code, id)
。也就是说,PRIMARY KEY
被隐式地添加到任何二级密钥上。第二个查询只需要country_code
和id
,因此可以完全在索引中执行,如Using index
所示。它按顺序读取索引并传递结果。很有效率。
现在,让我们看看第一个查询。这次您要求*
,而不仅仅是id
。其余字段不在索引中。如果要使用索引(并且您可以使用... FROM city FORCE INDEX(CountryCode) ...
进行测试),则必须执行此操作:
ids
,但不会提供*
的其余部分。*
的数据。这是昂贵的,特别是如果表不能完全缓存。相反,如果它执行了“表扫描”(这是您所看到的),代码的工作方式如下:
MEMORY
或MyISAM
。)表扫描+排序可能更快。
其他说明
如果你的城市在美国,那么新墨西哥州的“Los Ranchos de Albuquerque”对于这个领域来说太长了。对于这个世界,考虑在KZ的87-char“Imeni 50-letiya(Pyat'desyatiletiya)Kazakhskoy Sovetskoy Sotsialisticheskoy Respubliki”。
不要将CHAR
用于可变长度字符串(城市,地区);使用VARCHAR
;它在空间上会更有效率,因此速度更快。
使用CHAR(3)
作为固定长度的country_code
,但请务必指定CHARACTER SET ascii
。如果使用默认值utf8,则需要9个字节,而不是3个字节。