首先声明,我是一个菜鸟。一下文章中出现技术误导情况盖不负责
前端时间跟一个DB相干的项目,alanc反馈有一个查询,应用索引比不应用索引慢很多倍,有点毁三不雅。所以跟进了一下,用explain,看了看2个查询不同的结果。
不必索引的查询的时候结果如下,实际查询中速度比较块。
mysql> explain select * from rosterusers limit 10000,3 ;
+----+-------------+-------------+------+---------------+------+---------+------+---------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+---------+-------+
| 1 | SIMPLE | rosterusers | ALL | NULL | NULL | NULL | NULL | 2010066 | |
+----+-------------+-------------+------+---------------+------+---------+------+---------+-------+
而应用索引order by的查询结果如下,速度反而慢的惊人。
mysql> explain select * from rosterusers order by username limit 10000,3 ;
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------+
| 1 | SIMPLE | rosterusers | ALL | NULL | NULL | NULL | NULL | 2010087 | Using filesort |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------+
区别在于,应用索引查询的Extra变成了,Using filesort。居然用了应用外部文件进行排序。这个当然慢了。
但数据表上在username,的确是有索引的。怎么会反而要Using filesort?
看了一下数据表定义。是一个开源聊天服务器ejabberd的一张表。初看以为主键i_rosteru_user_jid是username,和jid的结合索引,那么应用order by username时应该是可以应用到索引才对呀?
CREATE TABLE `rosterusers` (
`username` varchar(250) NOT NULL,
`jid` varchar(250) NOT NULL,
UNIQUE KEY `i_rosteru_user_jid` (`username`(75),`jid`(75)),
KEY `i_rosteru_jid` (`jid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
仔细检查突然发明其主键定义,不是定义的完整的主键名称,而跟了一个75的长度描述,稍稍一愣,原来用的是前缀索引,而不是整个字段都是索引。(我的记忆里头InnoDB还不支持这玩意,估计是4.0后什么版本参加的),前缀索引就是将数据字段中前面N个字节作为索引的一种方法。。
发明了这个问题后,我们开始疑惑慢查询和这个索引有关,前缀索引的主要用途在于偶然字段进程,而MySQL支持的很多索引长度是有制约的。
首先不带order by 的limit 这种查询,本质可能还是和主键相干的,因为MySQL 的INNODB的操纵实际都是依靠主键的(即使你没有建立,系统也会有一个默许的),而limit这种查询,应用主键是可以加快速度,(explain返回的rows 应该是一个参考值),虽然我没有看见什么文档明白的说明过这个问题,但从不带order by 的limit 查询的返回结果基本可以证明这点。
但当我们应用order by username的时候,由于希望应用的是username的排序,而不是username(75)的排序,但实际索引是前缀索引,不是完整字段的索引。所以反而致使了order by的时候完整没法利用索引了。(我在SQL语句里头增长强制应用索引i_rosteru_user_jid也不起作用)。而其实应用中,表中的字段username 连75个都用不到,何况定义的250的长度。完整是自己折腾致使的费事。由于这是其他产品的表格,我们没法更改,临时只能先将就用不不带排序的查询讲究。
总结:
- 前缀索引,并不是一个万能药,他的确可以帮助我们对一个写过长的字段上建立索引。但也会致使排序(order by ,group by)查询上都是没法应用前缀索引的。
- 任何时候,对于DB Schema定义,合理的规划自己的字段长度,字段类型都是首要的事件。
【本文作者是雁渡寒潭,本着自在的精神,你可以在无红利的情况完整转载此文档,转载时请附上BLOG链接:http://www.cnblogs.com/fullsail/ 或者http://blog.csdn.net/fullsail,否则每字一元,每图一百不讲价。对Baidu文库,360doc加价一倍】
文章结束给大家分享下程序员的一些笑话语录:
IBM和波音777
波音777是有史以来第一架完全在电脑虚拟现实中设计制造的飞机,所用的设备完全由IBM公司所提供。试飞前,波音公司的总裁非常热情的邀请IBM的技术主管去参加试飞,可那位主管却说道:“啊,非常荣幸,可惜那天是我妻子的生日,So..”..
波音公司的总载一听就生气了:“胆小鬼,我还没告诉你试飞的日期呢!”