MySQL高性能的索引策略(一)mysql
基于如下表结构sql
create table article( id int auto_increment primary key, title varchar(255) not null, shortName varchar(255) not null, authorId int not null, createTime datetime not null, state int not null, totalView int default null, unique index idx_short_name_title (title,shortName) ); create table user ( id int auto_increment primary key, name varchar(255) not null, sex bit default 0, email varchar(50) not null, address varchar(255) default null, unique index idx_email (email), index idx_name (name) ); insert into article (title,shortName,authorId,createTime,state,totalView) values ('hello world','hello-world-0',1,'2015-10-11 08:08:08',1,10), ('hello world','hello-world-1',1,'2015-10-11 08:08:08',2,10), ('hello world','hello-world-2',2,'2015-10-11 08:08:08',3,10), ('hello world','hello-world-3',3,'2015-10-11 08:08:08',4,10), ('hello world','hello-world-4',3,'2015-10-11 08:08:08',5,10); insert into user (name,sex,email,address) values('lyx',0,'000@gmail.com','bj'), ('lyx',0,'111@gmail.com','bj'), ('lyx-0',0,'222@gmail.com','bj'), ('lyx-1',0,'333@gmail.com','bj');
若是查询中的列不是独立的,则mysql就不会使用索引,独立的列是指列不能是表达式的一部分,也不能是函数的参数。函数
> explain select * from article where id +1 = 2 ******************** 1. row ********************* id: 1 select_type: SIMPLE table: article type: ALL possible_keys: key: key_len: ref: rows: 5 Extra: Using where 1 rows in set
如上面所示,id时一个主键索引,但却没有使用索引查找数据,就是由于主键列不是单独的列,而下面,性能
> explain select * from article where id=1 ******************** 1. row ********************* id: 1 select_type: SIMPLE table: article type: const possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 1 Extra: 1 rows in set
一个type类型是all,而另外一个类型倒是const。spa
有时候须要索引很长的字符串,这会让索引变的大且慢。一个策略是前面提到过的模拟哈希索引。一般能够索引开始的部分字符,这样能够大大节约索引空间,从而提升索引效率。可是这样也会下降索引的选择性。索引的选择性是指,不重复的索引值。code
通常状况下,某个列前缀的选择性也是足够高的,足以知足查询性能。对于Blob,Text或者很长的VARCHAR类型的列,必须使用前缀索引,由于mysql不容许这些列的完整长度。诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)。前缀应该足够长,以便使得前缀索引的选择性接近于索引整个列。索引
如何决定前缀的合适长度。使用以下sql,rem
> select count(*) as cnt , left(title,3) as pref from article group by pref order by cnt desc limit 10 ******************** 1. row ********************* cnt: 6 pref: hel ******************** 2. row ********************* cnt: 2 pref: dem ******************** 3. row ********************* cnt: 1 pref: dei ******************** 4. row ********************* cnt: 1 pref: dii 4 rows in set
而后咱们在增长选择的前缀的长度,字符串
> select count(*) as cnt , left(title,5) as pref from article group by pref order by cnt desc limit 10 ******************** 1. row ********************* cnt: 6 pref: hello ******************** 2. row ********************* cnt: 1 pref: deii ******************** 3. row ********************* cnt: 1 pref: demo ******************** 4. row ********************* cnt: 1 pref: demo- ******************** 5. row ********************* cnt: 1 pref: diiii 5 rows in set
这样可选择性就好一些了。最终前缀的长度多少更好,咱们能够经过下面的sql来比较,it
> select count(distinct left(title,3)) / count(*)as pref3, count(distinct left(title,4)) / count(*) as pref4, count(distinct left(title,5)) / count(*) as pref5 from article ******************** 1. row ********************* pref3: 0.4000 pref4: 0.4000 pref5: 0.5000 1 rows in set
咱们能够看到,当前缀长度3和4的时候是同样的,当前缀长度为5的时候,前缀索引的选择性就降低了。
那么肯定的索引前缀的长度为3,而后创建索引。
alter table article add index idx_title(title(3));
==========END==========