梦想一步登天

导航

MySQL索引

 索引是对数据库表中一个或多个列(例如,user 表的姓名 (name) 列)的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。

例如这样一个查询:select * from table1 where id=10000。如果没有索引,必须遍历整个表,直到ID等于10000的这一行被找到为止;有了 索引之后(必须是在ID这一列上建立的索引),即可在索引中查找。由于索引是经过某种算法优化过的,因而查找次数要少的多。可见,索引插叙的速度要比没有索引的速度要快很多

MySQL中常见索引有:

  • 普通索引
  • 唯一索引
  • 主键索引
  • 组合索引

 

一、普通索引(index)

普通所以只有一个功能,就是加快查找速度。操作如下

1、先创建一个表

create table tab1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)  //添加索引,将Name列设置为索引
)

2、创建表索引

create index 索引名称 on 表名(列名)

3、删除索引

drop 索引名称 on 表名;

4、查看索引

show index from 表名;

5、注意事项(对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。)

create index index_name on tab1(extra(32));

 

二、唯一索引(unique)

唯一性索引unique index和一般索引normal index最大的差异就是在索引列上增加了一层唯一约束。添加唯一性索引的数据列可以为空,但是只要存在数据值,就必须是唯一的。

1、创建表+唯一索引

create table tab2(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    unique ix_name (name)  -- 重点在这里
)

2、创建唯一索引

create unique index 索引名 on 表名(列名)

3、删除唯一索引

drop unique index 索引名 on 表名

 

三、主键索引

在数据库关系图中为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型。主键索引要求主键中的每个值是唯一的。当在查询中使用主键索引时,它还允许快速访问数据。数据不能为空

1、创建表+主键索引

create table in1(
    nid int not null auto_increment,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    primary key(nid),
    index pri_index (name)
)

2、创建主键索引

alter table 表名 add primary key(列名);

3、删除主键

alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

 

四、组合索引

组合索引,就是组合查询的意思,将两列或者多列组合成一个索引进行查询

其应用场景为:频繁的同时使用n列来进行查询,如:select * from where name = 'admin' and email = 'admin@163.com'。

1、创建表组合索引

create table tb3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index x_index (name,email)    

       
)

如上创建组合索引之后,查询有的会使用索引,有的不会:

  • name and email  -- 使用索引
  • name                 -- 使用索引
  • email                 -- 不使用索引

 

五、使用索引的注意事项

1、正确使用索引

数据库表中添加索引后能够让查询数据库速度飞快,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。

下面这些情况不会使用到索引:

1、like '%xx'
    select * from tb1 where name like '%cn';

2、使用函数
    select * from tb1 where reverse(name) = 'admin';

3、or
    select * from tb1 where nid = 1 or email='admin@live.com';
    特别的:当or条件中有未建立索引的列才失效,以下会走索引
            select * from tb1 where nid = 1 or name = 'admin';
            select * from tb1 where nid = 1 or email = 'admin@live.com' and name = 'admin'

4、类型不一致
    如果列是字符串类型,传入条件是必须用引号引起来,不然...
    select * from tb1 where name = 999;

5、 !=
    select * from tb1 where name != 'admin'
    特别的:如果是主键,则还是会走索引
        select * from tb1 where nid != 123

6、 >
    select * from tb1 where name > 'admin'
    特别的:如果是主键或索引是整数类型,则还是会走索引
        select * from tb1 where nid > 123
        select * from tb1 where num > 123

7、order by
    select email from tb1 order by name desc;
    当根据索引排序时候,选择的映射如果不是索引,则不走索引
    特别的:如果对主键排序,则还是走索引:
        select * from tb1 order by nid desc;
 
8、 组合索引最左前缀
    如果组合索引为:(name,email)
    name and email       -- 使用索引
    name                 -- 使用索引
    email                -- 不使用索引

2、其他注意事项

  • 避免使用select *
  • count(1)或count(列) 代替 count(*)
  • 创建表时尽量时 char 代替 varchar
  • 表的字段顺序固定长度的字段优先
  • 组合索引代替多个单列索引(经常使用多个条件查询时)
  • 尽量使用短索引
  • 使用连接(JOIN)来代替子查询(Sub-Queries)
  • 连表时注意条件类型需一致
  • 索引散列值(重复少)不适合建索引,例:性别不适合

3、执行计划

explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

mysql> explain select * from tb2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
 1 id
 2         查询顺序标识
 3             如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
 4             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
 5             | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
 6             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
 7             |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
 8             |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
 9             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
10         特别的:如果使用union连接气值可能为null
11 
12 
13     select_type
14         查询类型
15             SIMPLE          简单查询
16             PRIMARY         最外层查询
17             SUBQUERY        映射为子查询
18             DERIVED         子查询
19             UNION           联合
20             UNION RESULT    使用联合的结果
21             ...
22     table
23         正在访问的表名
24 
25 
26     type
27         查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
28             ALL             全表扫描,对于数据表从头到尾找一遍
29                             select * from tb1;
30                             特别的:如果有limit限制,则找到之后就不在继续向下扫描
31                                    select * from tb1 where email = 'seven@live.com'
32                                    select * from tb1 where email = 'seven@live.com' limit 1;
33                                    虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。
34 
35             INDEX           全索引扫描,对索引从头到尾找一遍
36                             select nid from tb1;
37 
38             RANGE          对索引列进行范围查找
39                             select *  from tb1 where name < 'alex';
40                             PS:
41                                 between and
42                                 in
43                                 >   >=  <   <=  操作
44                                 注意:!= 和 > 符号
45 
46 
47             INDEX_MERGE     合并索引,使用多个单列索引搜索
48                             select *  from tb1 where name = 'alex' or nid in (11,22,33);
49 
50             REF             根据索引查找一个或多个值
51                             select *  from tb1 where name = 'seven';
52 
53             EQ_REF          连接时使用primary key 或 unique类型
54                             select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
55 
56 
57 
58             CONST           常量
59                             表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
60                             select nid from tb1 where nid = 2 ;
61 
62             SYSTEM          系统
63                             表仅有一行(=系统表)。这是const联接类型的一个特例。
64                             select * from (select nid from tb1 where nid = 1) as A;
65     possible_keys
66         可能使用的索引
67 
68     key
69         真实使用的
70 
71     key_len
72         MySQL中使用索引字节长度
73 
74     rows
75         mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值
76 
77     extra
78         该列包含MySQL解决查询的详细信息
79         “Using index”
80             此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
81         “Using where82             这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
83         “Using temporary”
84             这意味着mysql在对查询结果排序时会使用一个临时表。
85         “Using filesort”
86             这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
87         “Range checked for each record(index map: N)”
88             这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。
explain命令详细说明

 

 

 

 

 

 

 

 

posted on 2020-01-04 14:16  梦想一步登天  阅读(186)  评论(0编辑  收藏  举报