MySQL高性能的索引策略(一)

MySQL高性能的索引策略(一)

基于以下表结构

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,'[email protected]','bj'),
('lyx',0,'[email protected]','bj'),
('lyx-0',0,'[email protected]','bj'),
('lyx-1',0,'[email protected]','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。


前缀索引和索引选择性

有时候需要索引很长的字符串,这会让索引变的大且慢。一个策略是前面提到过的模拟哈希索引。通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率。但是这样也会降低索引的选择性。索引的选择性是指,不重复的索引值。

一般情况下,某个列前缀的选择性也是足够高的,足以满足查询性能。对于Blob,Text或者很长的VARCHAR类型的列,必须使用前缀索引,因为mysql不允许这些列的完整长度。诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)。前缀应该足够长,以便使得前缀索引的选择性接近于索引整个列。

如何决定前缀的合适长度。使用如下sql,

> 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来比较,

> 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==========

你可能感兴趣的:(MySQL高性能的索引策略(一))