mysql 索引

2020-01-13

索引:做约束,加速查询(btree索引)//相当于将数据列建立一个目录,查询时直接定位到指定数据
除空间索引外,InnoDB索引均为B树数据结构。空间索引使用R树,R树是用于索引多维数据的专用数据结构。索引记录存储在其B树或R树数据结构的叶页中。索引页的默认大小为16KB。
InnoDB创建或重建索引时,执行一次批量加载,而不是一次插入一个索引记录。这种索引创建方法也称为排序索引构建。空间索引不支持排序索引构建。
索引构建分为三个阶段
在第一阶段将扫描聚簇索引,并生成索引条目并将其添加到排序缓冲区。当排序缓冲区已满时,将对条目进行排序并将其写到临时中间文件中。此过程也称为“运行”。
在第二阶段中,当一次或多次“运行”写入临时中间文件时,对文件中的所有条目执行合并排序。
在第二阶段,将已排序的条目插入B-tree中。

缺点:占据硬盘空间,插入、更新速度下降,(需要在表文件及索引文件都插入数据),(数据量大时 创建索引时也比较慢)
or可能是两侧的索引都失效
索引使用场景:查询次数远大于插入、更新次数时创建索引才比较好
数据存储方式:
                      30
 
        10                        40
 
   5         15            35             66
 
1   6     11    19      21      39     55     100

外键索引

注意:对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。

普通索引://加速查询
//创建表+索引
create table in1(
        nid int not null auto_increment primary key,
        name varchar(32) not null,
        email varchar(64) not null,
        extra text,
        index ix_name (name)//索引 //index表示创建索引 //ix_name 索引的名字  //(name) 索引的列
    )
create index index_name on table_name(column_name)
删除索引
drop index_name on table_name;
查看索引
show index from table_name;

唯一索引 //加速查询,约束一列数据不能重复
创建表+索引
create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    unique ix_name (name)
)
创建索引
create unique index 索引名 on 表名(列名)
删除索引
drop unique index 索引名 on 表名

主键索引://加速查询 和 唯一约束(不可含null)
创建索引+主键
create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
)

OR

create table in1(
    nid int not null auto_increment,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    primary key(ni1),
    index ix_name (name) 
)
创建主键
alter table 表名 add primary key(列名);
删除主键
alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

组合索引://组合索引是将n个列组合成一个索引,其应用场景为:频繁的同时使用n列来进行查询
最左匹配,查询时的条件必须与索引的顺序相同才会使用索引:
例:create index ix_name_email on in3(name,email);
select * from in3 where name="1" and email="123"; 会使用索引
select * from in3 where email="123" and name="1"; 不会使用索引
select * from in3 where name="1"; 不会使用索引


普通组合索引:无约束
联合唯一索引:有约束,两列数据同时不相同,才能插入,不然报错

创建表
create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
)

创建索引:create index ix_name_email on in3(name,email);

如上创建组合索引之后,查询:

name and email  -- 使用索引
name                 -- 使用索引
email                 -- 不使用索引
注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并。


普通的索引:select nid from tb where nid = 10;先去索引中找,再去数据表表操作
覆盖索引:应用上索引,并且不用去数据表中操作,只需要在索引表中就能获取数据
如:查询nid小于10的nid值
select nid from tb where nid < 10;(只在索引中找)

合并索引: 使用多个单独索引查询  缺点:更占空间(每个索引一个索引表)
name(单独索引)  email(单独索引) pwd
select * from tb where name="alex";  会使用索引
select * from tb where email="alex@163.com";  会使用索引
select * from tb where name="alex" or email="alex@163.com"; 会使用索引

组合索引:  单独使用时,除了最左的索引会生效,其他索引不会生效
nid name(组)  email(合) pwd
select * from tb where name="alex";  会使用索引
select * from tb where email="alex@163.com";  不会使用索引
select * from tb where name="alex" or email="alex@163.com"; 会使用索引

聚集索引
每个InnoDB表都有一个聚集索引,用于行中的数据被存储。通常,聚集索引与主键同义 。
在a表上定义PRIMARY KEY时,InnoDB将其用作聚集索引。
如果不为表定义PRIMARY KEY时,MySQL定位第一个UNIQUE、所有的键列NOT NULL的索引,并InnoDB使用它作为聚集索引。
如果表中没有PRIMARY KEY或合适的UNIQUE索引,InnoDB内部会在一个包含行ID值的合成列上生成一个名为GEN_CLUST_INDEX的隐藏聚集索引。这些行是按照InnoDB给表中的行分配的ID排序的。行ID是一个6字节的字段,在插入新行时单调地增加。因此,按行ID排序的行在物理上是按插入顺序排列的。

二级索引
除聚集索引以外的所有索引被称为二级索引(辅助索引)。在中InnoDB,辅助索引中的每个记录都包含该行的主键列以及为辅助索引指定的列。 InnoDB使用此主键值在聚集索引中搜索行。
如果主键较长,则辅助索引将使用更多空间,因此具有较短的主键是有利的。

 

对索引进行范围查询:
between and、in 、>、>= 、<、<=操作  
!= 和 >不走索引(普通)
!= 会走主键索引

> 会走主键或整数类型的索引

合并索引:explain语句时 type为index_merge

根据索引查询一个或多个值时 explain语句时 type 为REF(普通索引)

链接时使用主键或唯一索引时 explain语句时 type 为EQ_REF

CONST 常量(效率最高)
explain select nid from tb1 where nid=10; 覆盖索引

SYSTEM (效率最高)


命中索引:
like  左模糊不走索引 右模糊走索引  查询列时,在列上使用函数做计算时,不会使用索引

or 当or条件中有未建立索引的列时会失效,

数据类型不同也不走索引 如:索引类型为varchar 查询内容为int,那么将不会走索引

order by 根据索引排序时,选择的映射如果不是索引,则不走索引,对主键排序,会走索引
例:
select * from tb1 order by name desc; 不走索引
select name from tb1 order by name desc; 走索引
select * from tb1 order by id desc; 走索引

查看索引使用情况
show status like '%Handler_read%';
Handler_read_key  索引被用到的次数 越大越好
Handler_read_rnd_next  值越大,执行效率越差

多表查询索引使用:
(5.7的版本中常用的多表查询官方都进行了索引优化)
原来的版本:嵌套查询可能会导致外面的条件的索引失效,而里面的查询的索引生效
select name from students where class_id in (select id from class);

避免使用select *
使用count(1) 或count(列) 代替count(*)
创建表时尽量用 char 代替 varchar (char 比 varchar查询效率快)
创建表时固定长度的字段优先放在前面
组合索引代替多个单列索引(经常使用多个条件查询时)
尽量使用短索引  (指定列的前几个字符创建索引(当某列数据的前几个字符可以区分开数据时可以使用))(text,blod,必须指定长度创建索引)创建方法:
使用join连接代替字查询
连表时注意条件类型必须一致
索引散列值(重复少)不适合做索引 例:性别不合适

创建索引:

CREATE [UNIQUE | FULLTEXT ] INDEX index_name [index_type] ON tbl_name (key_part,...) [algorithm_option | lock_option]


key_part:
    col_name [(length)] [ASC | DESC]

index_type:
    USING {BTREE | HASH}

algorithm_option:
    ALGORITHM [=] {DEFAULT | INPLACE | COPY}

lock_option:
    LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}

col_name(length) :前缀索引(只支持char  varchar text binary varbinary blob)对于非二进制字符串类型,前缀长度以字符长度给出;对于二进制字符串类型,前缀长度以字节长度给出
唯一索引:如果指定前缀索引,那么在指定的前缀长度内容必须唯一
全文索引:不支持前缀索引


USING {BTREE | HASH}:
对于NDB表列上的索引,USING只能为唯一索引或主键指定该选项。 USING HASH防止创建有序索引;否则,在NDB表上创建唯一索引或主键会自动导致同时创建有序索引和哈希索引,每个索引都索引同一组列
对于包含NULL的一个或多个列的唯一索引的表, NDB哈希索引只能用于查找文字值,这意味着 IS [NOT] NULL条件需要对表进行全面扫描。一种解决方法是,确保NULL 始终使用这样的表创建使用一个或多个列的唯一索引,以使其包含有序索引;也就是说,USING HASH在创建索引时避免使用
 

索引类型:
myisam、innodb 支持 BTREE索引
memory/heap 支持BTREE、HASH索引
NDB 支持BTREE、HASH索引

innodb/myisam索引说明
主键(Primary key) btree索引 没有存储空间 不允许有null值,不适用于is null和is not null
唯一索引(unique) btree索引 有存储空间 可以有null值,is null和is not null使用索引
key btree索引 有存储空间 可以有null值,is null和is not null使用索引
全文索引(fulltext) 没有索引类型 没有存储空间 可以有null值,is null和is not null扫表

删除索引

DROP INDEX index_name ON tbl_name
#要删除主键,索引名称始终为 PRIMARY,由于PRIMARY是保留字,因此必须将其指定为带引号的标识符:
DROP INDEX `PRIMARY` ON t;

随机插入二级索引或从二级索引中删除可能导致索引碎片化。碎片意味着磁盘上索引页的物理排序与页上记录的索引排序不接近,或者64页块中有许多未使用的页已分配给索引。
碎片的一个症状是表占用的空间超过了它应“占用”的空间。确切多少是很难确定的。所有InnoDB数据和索引都存储在B树中,它们的填充因子可能在50%到100%之间变化。碎片化的另一个症状是,这样的表扫描花费的时间比“应该”花费的时间更多
为了加快索引扫描的速度,您可以定期执行 ALTER TABLE 操作,这会导致MySQL重建表:

ALTER TABLE tbl_name ENGINE=INNODB

如果对同一个表有很多查询,测试不同的列组合,请尝试创建少量的串联索引,而不是大量的单列索引。如果索引包含结果集所需的所有列(称为覆盖索引),则查询可能完全避免读取表数据

不要为每一列创建单独的二级索引,因为每个查询只能使用一个索引。很少查询的列或只有几个不同值的列上的索引可能对任何查询都没有帮助

执行联接从其他表中检索行时。如果声明相同的类型和大小,MySQL可以更有效地在列上使用索引。在这种情况下, VARCHAR与 CHAR被认为是相同的,如果它们被声明为相同的大小。例如, VARCHAR(10)和 CHAR(10)是相同的大小,但是 VARCHAR(10)和 CHAR(15)不是。如果不能不通过转换直接比较值,则比较不同的列(例如,将字符串列与时间或数字列进行比较)可能会阻止使用索引。

所有存储引擎每个表至少支持16个索引,一个索引最多可以包含16列,并且索引总长度至少为256个字节。前缀索引最长可以为1000个字节(InnoDB表中为767个字节 ,除非已设置innodb_large_prefix

如果col1col2上存在多列索引,则可以直接获取相应的行。如果col1col2上存在单独的单列索引,那么优化器将尝试使用索引合并优化

{/if}